ksyun-sdk-node 1.0.5 → 1.4.8

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.
Files changed (133) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/dist/base/BaseClient.js +133 -52
  3. package/dist/index.js +9 -12
  4. package/dist/lib/fetch.js +4 -5
  5. package/dist/lib/sign.js +31 -33
  6. package/dist/lib/signautreV4.js +167 -0
  7. package/dist/service/Actiontrail/v20190401/index.js +34 -37
  8. package/dist/service/Aicp/v20240612/index.js +511 -0
  9. package/dist/service/Bill/v20180601/index.js +49 -88
  10. package/dist/service/Bill/v20220601/index.js +64 -0
  11. package/dist/service/Bill_union/v20200101/index.js +151 -77
  12. package/dist/service/Bill_union/v20221222/index.js +142 -0
  13. package/dist/service/Bill_union/v20250801/index.js +66 -0
  14. package/dist/service/Bws/v20160304/index.js +111 -94
  15. package/dist/service/Cdn/v20160901/index.js +89 -0
  16. package/dist/service/Cdn/v20200630/index.js +410 -0
  17. package/dist/service/Cdn/v20200901/index.js +162 -0
  18. package/dist/service/Cdn/v20211201/index.js +45 -0
  19. package/dist/service/Cdn/v20250503/index.js +71 -0
  20. package/dist/service/Cen/v20160304/index.js +460 -0
  21. package/dist/service/Clickhouse/v20210101/index.js +546 -0
  22. package/dist/service/Ebs/v20160304/index.js +265 -268
  23. package/dist/service/Eip/v20160304/index.js +104 -107
  24. package/dist/service/Epc/v20151101/index.js +1735 -784
  25. package/dist/service/Iam/v20151101/index.js +872 -711
  26. package/dist/service/Iam/v20240513/index.js +47 -0
  27. package/dist/service/Iam/v20240703/index.js +44 -0
  28. package/dist/service/Kad/v20161122/index.js +84 -87
  29. package/dist/service/Kce/v20180314/index.js +320 -0
  30. package/dist/service/Kce/v20190806/index.js +482 -0
  31. package/dist/service/Kce/v20201231/index.js +63 -0
  32. package/dist/service/Kcf/v20211215/index.js +203 -0
  33. package/dist/service/Kcm/v20160304/index.js +120 -0
  34. package/dist/service/Kcrs/v20211109/index.js +851 -0
  35. package/dist/service/Kcs/v20160701/index.js +1106 -0
  36. package/dist/service/Kcs/v20170401/index.js +81 -0
  37. package/dist/service/Kead/v20200101/index.js +28 -31
  38. package/dist/service/Kec/v20160304/index.js +1695 -1466
  39. package/dist/service/Kes/v20201215/index.js +171 -0
  40. package/dist/service/Ket/v20170101/index.js +141 -0
  41. package/dist/service/Kkms/v20160304/index.js +167 -0
  42. package/dist/service/Klog/v20200731/index.js +331 -0
  43. package/dist/service/Kls/v20170101/index.js +194 -0
  44. package/dist/service/Kmr/v20210902/index.js +422 -0
  45. package/dist/service/Kmr/v20231231/index.js +154 -0
  46. package/dist/service/Kmr/v20240814/index.js +370 -0
  47. package/dist/service/Krds/v20160701/index.js +1302 -0
  48. package/dist/service/Krds/v20200825/index.js +174 -0
  49. package/dist/service/Memcached/v20180627/index.js +249 -0
  50. package/dist/service/Mongodb/v20170101/index.js +516 -501
  51. package/dist/service/Monitor/v20100525/index.js +70 -0
  52. package/dist/service/Monitor/v20181114/index.js +49 -0
  53. package/dist/service/Monitor/v20210101/index.js +216 -0
  54. package/dist/service/Monitor/v20220101/index.js +58 -0
  55. package/dist/service/Monitor/v20250101/index.js +71 -0
  56. package/dist/service/Rabbitmq/v20191017/index.js +242 -0
  57. package/dist/service/Resourcemanager/v20210320/index.js +113 -116
  58. package/dist/service/Sks/v20151101/index.js +72 -75
  59. package/dist/service/Slb/v20160304/index.js +1299 -790
  60. package/dist/service/Sts/v20151101/index.js +26 -29
  61. package/dist/service/Tagv2/v20200901/index.js +174 -0
  62. package/dist/service/Tidb/v20210520/index.js +363 -0
  63. package/dist/service/Trade/v20200114/index.js +23 -26
  64. package/dist/service/Trade/v20200831/index.js +25 -28
  65. package/dist/service/Vpc/v20160304/index.js +2015 -1045
  66. package/dist/service/Waf/v20200707/index.js +248 -0
  67. package/example/iam.js +2 -1
  68. package/example/res.js +2 -1
  69. package/package.json +1 -1
  70. package/src/base/BaseClient.js +131 -35
  71. package/src/lib/signautreV4.js +166 -0
  72. package/src/service/Actiontrail/v20190401/index.js +42 -42
  73. package/src/service/Aicp/v20240612/index.js +503 -0
  74. package/src/service/Bill/v20180601/index.js +61 -102
  75. package/src/service/Bill/v20220601/index.js +56 -0
  76. package/src/service/Bill_union/v20200101/index.js +181 -109
  77. package/src/service/Bill_union/v20221222/index.js +134 -0
  78. package/src/service/Bill_union/v20250801/index.js +58 -0
  79. package/src/service/Bws/v20160304/index.js +139 -119
  80. package/src/service/Cdn/v20160901/index.js +81 -0
  81. package/src/service/Cdn/v20200630/index.js +402 -0
  82. package/src/service/Cdn/v20200901/index.js +154 -0
  83. package/src/service/Cdn/v20211201/index.js +37 -0
  84. package/src/service/Cdn/v20250503/index.js +63 -0
  85. package/src/service/Cen/v20160304/index.js +452 -0
  86. package/src/service/Clickhouse/v20210101/index.js +538 -0
  87. package/src/service/Ebs/v20160304/index.js +365 -368
  88. package/src/service/Eip/v20160304/index.js +135 -136
  89. package/src/service/Epc/v20151101/index.js +1984 -1033
  90. package/src/service/Iam/v20151101/index.js +1155 -993
  91. package/src/service/Iam/v20240513/index.js +39 -0
  92. package/src/service/Iam/v20240703/index.js +36 -0
  93. package/src/service/Kad/v20161122/index.js +112 -112
  94. package/src/service/Kce/v20180314/index.js +312 -0
  95. package/src/service/Kce/v20190806/index.js +474 -0
  96. package/src/service/Kce/v20201231/index.js +55 -0
  97. package/src/service/Kcf/v20211215/index.js +195 -0
  98. package/src/service/Kcm/v20160304/index.js +112 -0
  99. package/src/service/Kcrs/v20211109/index.js +843 -0
  100. package/src/service/Kcs/v20160701/index.js +1098 -0
  101. package/src/service/Kcs/v20170401/index.js +73 -0
  102. package/src/service/Kead/v20200101/index.js +36 -36
  103. package/src/service/Kec/v20160304/index.js +2061 -1838
  104. package/src/service/Kes/v20201215/index.js +163 -0
  105. package/src/service/Ket/v20170101/index.js +133 -0
  106. package/src/service/Kkms/v20160304/index.js +159 -0
  107. package/src/service/Klog/v20200731/index.js +323 -0
  108. package/src/service/Kls/v20170101/index.js +186 -0
  109. package/src/service/Kmr/v20210902/index.js +414 -0
  110. package/src/service/Kmr/v20231231/index.js +146 -0
  111. package/src/service/Kmr/v20240814/index.js +362 -0
  112. package/src/service/Krds/v20160701/index.js +1294 -0
  113. package/src/service/Krds/v20200825/index.js +166 -0
  114. package/src/service/Memcached/v20180627/index.js +241 -0
  115. package/src/service/Mongodb/v20170101/index.js +672 -654
  116. package/src/service/Monitor/v20100525/index.js +62 -0
  117. package/src/service/Monitor/v20181114/index.js +41 -0
  118. package/src/service/Monitor/v20210101/index.js +208 -0
  119. package/src/service/Monitor/v20220101/index.js +50 -0
  120. package/src/service/Monitor/v20250101/index.js +63 -0
  121. package/src/service/Rabbitmq/v20191017/index.js +234 -0
  122. package/src/service/Resourcemanager/v20210320/index.js +157 -158
  123. package/src/service/Sks/v20151101/index.js +95 -96
  124. package/src/service/Slb/v20160304/index.js +1471 -959
  125. package/src/service/Sts/v20151101/index.js +34 -34
  126. package/src/service/Tagv2/v20200901/index.js +166 -0
  127. package/src/service/Tidb/v20210520/index.js +355 -0
  128. package/src/service/Trade/v20200114/index.js +31 -31
  129. package/src/service/Trade/v20200831/index.js +33 -33
  130. package/src/service/Vpc/v20160304/index.js +2404 -1432
  131. package/src/service/Waf/v20200707/index.js +240 -0
  132. package/src/service/Bill_union/v20211209/index.js +0 -35
  133. package/src/service/Slb/v20171210/index.js +0 -39
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+
3
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
+ const BaseClient = require("../../../base/BaseClient.js");
7
+ module.exports = class Client extends BaseClient {
8
+ constructor(...args) {
9
+ super(...args);
10
+ _defineProperty(this, "_baseConfig", {
11
+ protocol: "http://",
12
+ endpoint: "waf.api.ksyun.com",
13
+ config: {
14
+ timeout: 60,
15
+ //设置timeout
16
+ headers: {
17
+ Accept: "application/json"
18
+ },
19
+ credentials: {
20
+ region: "cn-shanghai-3",
21
+ service: "waf"
22
+ }
23
+ }
24
+ });
25
+ _defineProperty(this, "_apiList", {
26
+ CreateDomain: {
27
+ url: "/",
28
+ method: "GET",
29
+ config: {
30
+ query: {
31
+ Version: "2020-07-07",
32
+ Action: "CreateDomain"
33
+ },
34
+ headers: {
35
+ "Content-Type": "application/x-www-form-urlencoded"
36
+ }
37
+ },
38
+ paramsType: {
39
+ ResourceRecord: "String",
40
+ HttpRewrite: "Boolean",
41
+ HttpSource: "Boolean",
42
+ CertificateId: "String",
43
+ CertificateRegion: "String",
44
+ LbMethod: "String",
45
+ HasProxy: "Boolean",
46
+ ProjectId: "Int",
47
+ HeaderMark: "String",
48
+ HeaderValue: "String",
49
+ HealthMonitor: "String",
50
+ HttpPort: "Filter",
51
+ HttpsPort: "Filter",
52
+ Sources: "String"
53
+ }
54
+ },
55
+ DescribeDomains: {
56
+ url: "/",
57
+ method: "GET",
58
+ config: {
59
+ query: {
60
+ Version: "2020-07-07",
61
+ Action: "DescribeDomains"
62
+ },
63
+ headers: {
64
+ "Content-Type": "application/x-www-form-urlencoded"
65
+ }
66
+ },
67
+ paramsType: {
68
+ ResourceRecord: "String"
69
+ }
70
+ },
71
+ ModifyDomain: {
72
+ url: "/",
73
+ method: "GET",
74
+ config: {
75
+ query: {
76
+ Version: "2020-07-07",
77
+ Action: "ModifyDomain"
78
+ },
79
+ headers: {
80
+ "Content-Type": "application/x-www-form-urlencoded"
81
+ }
82
+ },
83
+ paramsType: {
84
+ ResourceRecordId: "String",
85
+ HttpRewrite: "Boolean",
86
+ HttpSource: "Boolean",
87
+ CertificateId: "String",
88
+ CertificateRegion: "String",
89
+ LbMethod: "String",
90
+ HasProxy: "Boolean",
91
+ ProjectId: "Int",
92
+ HeaderMark: "String",
93
+ HeaderValue: "String",
94
+ HealthMonitor: "String",
95
+ HttpPort: "Filter",
96
+ HttpsPort: "Filter",
97
+ Sources: "String"
98
+ }
99
+ },
100
+ DeleteDomain: {
101
+ url: "/",
102
+ method: "GET",
103
+ config: {
104
+ query: {
105
+ Version: "2020-07-07",
106
+ Action: "DeleteDomain"
107
+ },
108
+ headers: {
109
+ "Content-Type": "application/x-www-form-urlencoded"
110
+ }
111
+ },
112
+ paramsType: {
113
+ ResourceRecordId: "String"
114
+ }
115
+ },
116
+ CreateAccessControlRule: {
117
+ url: "/",
118
+ method: "GET",
119
+ config: {
120
+ query: {
121
+ Version: "2020-07-07",
122
+ Action: "CreateAccessControlRule"
123
+ },
124
+ headers: {
125
+ "Content-Type": "application/x-www-form-urlencoded"
126
+ }
127
+ },
128
+ paramsType: {
129
+ ResourceRecordId: "String",
130
+ RuleName: "String",
131
+ RuleType: "String",
132
+ ArgName: "String",
133
+ RuleData: "String",
134
+ MatchRule: "Int",
135
+ Level: "Int",
136
+ RuleAction: "Int",
137
+ Status: "Boolean"
138
+ }
139
+ },
140
+ DescribeAccessControlRules: {
141
+ url: "/",
142
+ method: "GET",
143
+ config: {
144
+ query: {
145
+ Version: "2020-07-07",
146
+ Action: "DescribeAccessControlRules"
147
+ },
148
+ headers: {
149
+ "Content-Type": "application/x-www-form-urlencoded"
150
+ }
151
+ },
152
+ paramsType: {
153
+ RuleId: "String",
154
+ ResourceRecordId: "String",
155
+ RuleName: "String"
156
+ }
157
+ },
158
+ ModifyAccessControlRule: {
159
+ url: "/",
160
+ method: "GET",
161
+ config: {
162
+ query: {
163
+ Version: "2020-07-07",
164
+ Action: "ModifyAccessControlRule"
165
+ },
166
+ headers: {
167
+ "Content-Type": "application/x-www-form-urlencoded"
168
+ }
169
+ },
170
+ paramsType: {
171
+ RuleId: "String",
172
+ RuleName: "String",
173
+ RuleType: "String",
174
+ RuleData: "String",
175
+ MatchRule: "String",
176
+ ArgName: "String",
177
+ Level: "Int",
178
+ RuleAction: "Int",
179
+ Status: "Boolean"
180
+ }
181
+ },
182
+ DeleteAccessControlRule: {
183
+ url: "/",
184
+ method: "GET",
185
+ config: {
186
+ query: {
187
+ Version: "2020-07-07",
188
+ Action: "DeleteAccessControlRule"
189
+ },
190
+ headers: {
191
+ "Content-Type": "application/x-www-form-urlencoded"
192
+ }
193
+ },
194
+ paramsType: {
195
+ RuleId: "String"
196
+ }
197
+ },
198
+ DescribeCertificates: {
199
+ url: "/",
200
+ method: "GET",
201
+ config: {
202
+ query: {
203
+ Version: "2020-07-07",
204
+ Action: "DescribeCertificates"
205
+ },
206
+ headers: {
207
+ "Content-Type": "application/x-www-form-urlencoded"
208
+ }
209
+ },
210
+ paramsType: {
211
+ Request: "String"
212
+ }
213
+ },
214
+ CreateIpv6Protection: {
215
+ url: "/",
216
+ method: "GET",
217
+ config: {
218
+ query: {
219
+ Version: "2020-07-07",
220
+ Action: "CreateIpv6Protection"
221
+ },
222
+ headers: {
223
+ "Content-Type": "application/x-www-form-urlencoded"
224
+ }
225
+ },
226
+ paramsType: {
227
+ ResourceRecordId: "Array"
228
+ }
229
+ },
230
+ DeleteIpv6Protection: {
231
+ url: "/",
232
+ method: "GET",
233
+ config: {
234
+ query: {
235
+ Version: "2020-07-07",
236
+ Action: "DeleteIpv6Protection"
237
+ },
238
+ headers: {
239
+ "Content-Type": "application/x-www-form-urlencoded"
240
+ }
241
+ },
242
+ paramsType: {
243
+ ResourceRecordId: "Array"
244
+ }
245
+ }
246
+ });
247
+ }
248
+ };
package/example/iam.js CHANGED
@@ -14,7 +14,8 @@ const clientConfig = {
14
14
  method: 'POST', // 请求方法 GET 或者 POST
15
15
  timeout: 60, // 请求超时时间秒
16
16
  protocol: '', // 协议 http:// 或者 https://
17
- endpoint: '' // 接入点域名 如 iam.api.ksyun.com
17
+ endpoint: '', // 接入点域名 如 iam.api.ksyun.com
18
+ path: '' // 自定义URL路径 如 /api/v1/xxx
18
19
  },
19
20
  }
20
21
  let client = new Client(clientConfig)
package/example/res.js CHANGED
@@ -14,7 +14,8 @@ const clientConfig = {
14
14
  method: '', // 请求方法 get 或者 post
15
15
  timeout: 60, // 请求超时时间秒
16
16
  protocol: 'http://', // 协议 http:// 或者 https://
17
- endpoint: '' // 接入点域名 如 iam.api.ksyun.com
17
+ endpoint: '', // 接入点域名 如 iam.api.ksyun.com
18
+ path: '' // 自定义URL路径 如 /api/v1/xxx
18
19
  },
19
20
  }
20
21
  let client = new Client(clientConfig)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ksyun-sdk-node",
3
- "version": "1.0.5",
3
+ "version": "1.4.8",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -1,4 +1,4 @@
1
- const getSignedParams = require('../lib/sign.js').getSignedParams
1
+ const {getSignatureHeaders, getCanonicalizedQuery} = require('../lib/signautreV4.js')
2
2
  const fetch = require('../lib/fetch.js')
3
3
  const dayjs = require('dayjs')
4
4
  const utc = require('dayjs/plugin/utc.js')
@@ -26,67 +26,163 @@ module.exports = class BaseClient {
26
26
  */
27
27
  request (apiAction, params = {}) {
28
28
 
29
+ params = this.formatParams(apiAction, params)
30
+
29
31
  let apiConfig = this._apiList[apiAction]
30
- let publicParams = {
31
- Accesskey: this.ak,
32
- Service: this._baseConfig.config.credentials.service,
33
- Action: apiAction,
34
- Version: apiConfig.config.query.Version,
35
- Timestamp: dayjs().utc().format('YYYY-MM-DDThh:mm:ss')+'Z',
36
- SignatureVersion: '1.0',
37
- SignatureMethod: 'HMAC-SHA256',
38
- Region: this.region || this._baseConfig.config.credentials.region,
39
- }
40
32
 
41
- let combainParams = {
42
- ...publicParams,
43
- ...params
33
+ let protocol = this.httpProfile.protocol || this._baseConfig.protocol
34
+ let endpoint = this.httpProfile.endpoint || this._baseConfig.endpoint
35
+ let method = (this.httpProfile.method || apiConfig.method).toUpperCase()
36
+ let region = this.region || this._baseConfig.config.credentials.region
37
+ let headers = {
38
+ ...(this._baseConfig.config.headers || {}),
39
+ ...(apiConfig.config.headers || {})
44
40
  }
45
41
 
46
- let signedParams = getSignedParams(combainParams, this.sk)
42
+ // 处理自定义path
43
+ let customPath = this.httpProfile.path || ''
44
+ // 清理path中的?参数
45
+ if (customPath && customPath.includes('?')) {
46
+ customPath = customPath.split('?')[0]
47
+ }
47
48
 
48
- let protocol = this.httpProfile.protocol || this._baseConfig.protocol
49
- let endpoint = this.httpProfile.endpoint || this._baseConfig.endpoint
50
- let method = this.httpProfile.method || apiConfig.method
49
+ // 处理path拼接,避免双斜杠
50
+ let finalPath = apiConfig.url
51
+ if (customPath) {
52
+ // 清理endpoint末尾的斜杠
53
+ endpoint = endpoint.replace(/\/+$/, '')
54
+ // 确保customPath以/开头
55
+ if (!customPath.startsWith('/')) {
56
+ customPath = '/' + customPath
57
+ }
58
+ finalPath = customPath
59
+ }
51
60
 
52
- let url = `${protocol}${endpoint}${apiConfig.url}`
53
- if (['GET', 'DELETE', 'OPTION', 'HEAD'].includes(method.toUpperCase())) {
54
- url += `?${qs.stringify(signedParams)}`
61
+ let query = apiConfig.config.query
62
+ if (['GET', 'OPTION', 'HEAD'].includes(method)) {
63
+ query = {
64
+ ...query,
65
+ ...params
66
+ }
55
67
  }
56
- let headers = {
57
- ...(this._baseConfig.config.headers || {}),
58
- ...(apiConfig.config.headers || {}),
59
- // 目前kop只支持application/x-www-form-urlencoded类型的签名解析
60
- 'Content-Type': 'application/x-www-form-urlencoded',
68
+
69
+ let body = this.getBody(method, headers['Content-Type'], params)
70
+
71
+ let signParams = {
72
+ path: finalPath,
73
+ query,
74
+ body: body || '',
75
+ headers,
76
+ host: endpoint,
77
+ method,
78
+ region,
79
+ service: this._baseConfig.config.credentials.service,
80
+ access_key: this.ak,
81
+ secret_key: this.sk,
61
82
  }
62
- let body = this.getBody(method, headers['Content-Type'], signedParams)
83
+
84
+ let signHeaders = getSignatureHeaders(signParams)
85
+
86
+ let url = `${protocol}${endpoint}${finalPath}?${getCanonicalizedQuery(query)}`
63
87
 
64
88
  let timeoutSecond = this.httpProfile.timeout || this._baseConfig.config.timeout
89
+
90
+ // 打印 curl 命令
91
+ this.printCurl(url, method, signHeaders, body)
92
+
65
93
  return fetch(url, {
66
94
  method: method,
67
95
  timeout: timeoutSecond * 1000,
68
- headers,
96
+ headers: signHeaders,
69
97
  body
70
98
  })
71
99
  }
100
+ /**
101
+ * 格式化参数,对Filter类型做扁平处理
102
+ * @param {string} apiAction 接口名
103
+ * @param {object} params 参数值
104
+ * @returns 格式化后的参数
105
+ */
106
+ formatParams (apiAction, params) {
107
+ let paramsType = this._apiList[apiAction].paramsType
108
+ if (!paramsType || params == null) {
109
+ return params
110
+ }
111
+ let res = {}
112
+ Object.keys(params).forEach(key => {
113
+ let type = paramsType[key]
114
+ // 这些类型不用处理,如果为null、undefined则排除掉
115
+ if (['String', 'Int', 'Double', 'Long', 'Boolean', 'Array'].includes(type) && params[key] != null) {
116
+ res[key] = params[key]
117
+ }
118
+ if (type == 'Filter' || type == 'Object') {
119
+ res = {
120
+ ...res,
121
+ ...this.formatFilter(key, params[key])
122
+ }
123
+ }
124
+ })
125
+ return res
126
+ }
127
+ formatFilter (pKey, value) {
128
+ let res = {}
129
+ Object.keys(value).forEach(key => {
130
+ let prefixName = `${pKey}.${key}`
131
+ let childValue = value[key]
132
+ if (typeof(childValue) == 'object') {
133
+ res = {
134
+ ...res,
135
+ ...this.formatFilter(prefixName, childValue)
136
+ }
137
+ } else {
138
+ res[prefixName] = childValue
139
+ }
140
+ })
141
+ return res
142
+ }
143
+
72
144
  /**
73
145
  * 获取body
74
146
  * @param {string} method 请求类型
75
147
  * @param {string} contentType
76
- * @param {object} signedParams 参数对象
148
+ * @param {object} params 参数对象
77
149
  * @returns {string}
78
150
  */
79
- getBody (method, contentType, signedParams) {
80
- if (!['POST', 'PUT'].includes(method.toUpperCase())) {
81
- return undefined
151
+ getBody (method, contentType, params) {
152
+ if (!['POST', 'PUT'].includes(method) || JSON.stringify(params) == '{}') {
153
+ return null
82
154
  }
83
155
  // 目前只有下面这两种
84
156
  if (contentType == 'application/x-www-form-urlencoded') {
85
- return qs.stringify(signedParams)
157
+ return qs.stringify(params, {
158
+ allowDots: true, // 对象转成a.b.c
159
+ arrayFormat: 'indices' // 数组转成a[0]=b&a[1]=c
160
+ })
86
161
  }
87
162
  if (contentType == 'application/json') {
88
- return JSON.stringify(signedParams)
163
+ return JSON.stringify(params)
89
164
  }
90
- return JSON.stringify(signedParams)
165
+ return JSON.stringify(params)
166
+ }
167
+
168
+ /**
169
+ * 打印 curl 命令
170
+ */
171
+ printCurl(url, method, headers, body) {
172
+ let curlCmd = `curl -X ${method} '${url}'`
173
+
174
+ // 添加 headers
175
+ Object.keys(headers).forEach(key => {
176
+ curlCmd += ` \\\n -H '${key}: ${headers[key]}'`
177
+ })
178
+
179
+ // 添加 body
180
+ if (body) {
181
+ curlCmd += ` \\\n -d '${body}'`
182
+ }
183
+
184
+ console.log('\n========== CURL 请求 ==========')
185
+ console.log(curlCmd)
186
+ console.log('================================\n')
91
187
  }
92
188
  }
@@ -0,0 +1,166 @@
1
+ const crypto = require("crypto-js")
2
+ const dayjs = require('dayjs')
3
+ const utc = require('dayjs/plugin/utc.js')
4
+
5
+ dayjs.extend(utc)
6
+
7
+ const HEADERS_TO_IGNORE = {
8
+ 'cache-control' : true,
9
+ 'content-type' : true,
10
+ 'content-length' : true,
11
+ 'expect' : true,
12
+ 'max-forwards' : true,
13
+ 'pragma' : true,
14
+ 'range' : true,
15
+ 'te' : true,
16
+ 'if-match' : true,
17
+ 'if-none-match' : true,
18
+ 'if-modified-since' : true,
19
+ 'if-unmodified-since' : true,
20
+ 'if-range' : true,
21
+ 'accept' : true,
22
+ 'authorization' : true,
23
+ 'proxy-authorization' : true,
24
+ 'from' : true,
25
+ 'referer' : true,
26
+ 'user-agent' : true
27
+ }
28
+
29
+ function getSignatureKey(key, dateStamp, regionName, serviceName) {
30
+ var kDate = crypto.HmacSHA256(dateStamp, "AWS4" + key);
31
+ var kRegion = crypto.HmacSHA256(regionName, kDate);
32
+ var kService = crypto.HmacSHA256(serviceName, kRegion);
33
+ var kSigning = crypto.HmacSHA256("aws4_request", kService);
34
+ return kSigning;
35
+ }
36
+
37
+ /**
38
+ * 编码
39
+ * @param {*} str
40
+ * @returns
41
+ */
42
+ function encodeRfc3986Full(str) {
43
+ // This function assumes the string has already been percent encoded
44
+ function encodeRfc3986(urlEncodedString) {
45
+ return urlEncodedString.replace(/[!'()*]/g, function (c) {
46
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
47
+ })
48
+ }
49
+ return encodeRfc3986(encodeURIComponent(str))
50
+ }
51
+
52
+ /**
53
+ *
54
+ * @param {*} path
55
+ * @returns
56
+ */
57
+ function createCanonicalizedPath(path) {
58
+ return encodeRfc3986Full(path).replace(/%2F/g, '/')
59
+ }
60
+
61
+ function getCanonicalHeaders(headers) {
62
+ function trimAll(header) {
63
+ return header.toString().trim().replace(/\s+/g, ' ')
64
+ }
65
+ return Object.keys(headers)
66
+ .filter(function (key) { return HEADERS_TO_IGNORE[key.toLowerCase()] == null })
67
+ .sort(function (a, b) { return a.toLowerCase() < b.toLowerCase() ? -1 : 1 })
68
+ .map(function (key) { return key.toLowerCase() + ':' + trimAll(headers[key]) })
69
+ .join('\n') + '\n'
70
+ }
71
+
72
+ function getSignedHeaders(headers) {
73
+ return Object.keys(headers)
74
+ .map(function (key) { return key.toLowerCase() })
75
+ .filter(function (key) { return HEADERS_TO_IGNORE[key] == null })
76
+ .sort()
77
+ .join(';')
78
+ }
79
+
80
+
81
+ function getCanonicalizedQuery(query) {
82
+ if (!query) {
83
+ return ''
84
+ }
85
+ delete query['X-Amz-Signature'] // php项目里有这句
86
+ let res = [];
87
+ let sortKeys = Object.keys(query).sort()
88
+ sortKeys.forEach(key => {
89
+ if (!Array.isArray(query[key])) {
90
+ res.push(encodeRfc3986Full(key) + '=' + encodeRfc3986Full(query[key]))
91
+ } else {
92
+ query[key].map(encodeRfc3986Full).sort().forEach(val => {
93
+ res.push(encodeRfc3986Full(key) + '=' + encodeRfc3986Full(val))
94
+ })
95
+ }
96
+ })
97
+ return res.join('&')
98
+ }
99
+
100
+ // 签名步骤摘要
101
+ // 要创建已签名的请求,请完成以下操作:
102
+
103
+ /**
104
+ * 获取包含签名的头,含之前的头
105
+ * AWS Version 4
106
+ * https://docs.aws.amazon.com/zh_cn/general/latest/gr/sigv4_signing.html
107
+ * @param {string} path
108
+ * @param {string} query
109
+ */
110
+ function getSignatureHeaders({
111
+ path, query, body, headers, host, method, region, service, secret_key, access_key
112
+ }) {
113
+
114
+ let now = dayjs().utc()
115
+ let amzdate = now.format(`YYYYMMDDTHHmmssZ`)
116
+ let datestamp = now.format('YYYYMMDD')
117
+
118
+ // 任务 1:针对签名版本 4 创建规范请求
119
+ // 将请求的内容(主体、操作、标头等)组织为标准(规范)格式。规范请求是用于创建待签字符串的输入之一。
120
+
121
+ let canonical_uri = createCanonicalizedPath(path)
122
+ let canonical_querystring = getCanonicalizedQuery(query)
123
+
124
+ let allHeaders = {
125
+ ...headers,
126
+ host,
127
+ 'x-amz-date': amzdate
128
+ }
129
+ let canonical_headers = getCanonicalHeaders(allHeaders)
130
+ let signed_headers = getSignedHeaders(allHeaders)
131
+
132
+ let payload_hash = headers['X-Amz-Content-Sha256'] || headers['x-amz-content-sha256'] ||
133
+ crypto.SHA256(body || '').toString()
134
+
135
+ let canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash
136
+
137
+
138
+ // 任务 2:创建签名版本 4 的待签字符串
139
+ // 使用规范请求和额外信息(例如算法、请求日期、凭证范围和规范请求的摘要(哈希))创建待签字符串。
140
+ let algorithm = 'AWS4-HMAC-SHA256'
141
+ let credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'
142
+ let string_to_sign = algorithm + '\n' + amzdate + '\n' + credential_scope + '\n' + crypto.SHA256(canonical_request).toString()
143
+
144
+ // 任务 3:为AWS签名版本 4 计算签名
145
+ // 使用AWS秘密访问密钥作为初始哈希操作的密钥,对请求日期、区域和服务执行一系列加密哈希操作(HMAC 操作),从而派生签名密钥。在派生签名密钥后,通过对待签字符串执行加密哈希操作来计算签名。使用派生的签名密钥作为此操作的哈希密钥。
146
+ let signing_key = getSignatureKey(secret_key, datestamp, region, service);
147
+ let signature = crypto.HmacSHA256(string_to_sign, signing_key).toString();
148
+
149
+ // 任务 4:将签名添加到 HTTP 请求
150
+ // 在计算签名后,将其添加到请求的 HTTP 标头或查询字符串中。
151
+ let authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature
152
+
153
+ let res = {
154
+ ...headers
155
+ }
156
+ res['x-amz-date'] = amzdate
157
+ res['Authorization'] = authorization_header
158
+
159
+ return res
160
+
161
+ }
162
+
163
+ module.exports = {
164
+ getCanonicalizedQuery,
165
+ getSignatureHeaders
166
+ }