UNPKG

3.97 kBPlain TextView Raw
1import TencentCloudSDKHttpException from "./exception/tencent_cloud_sdk_exception"
2import * as crypto from "crypto"
3import { URL } from "url"
4
5/**
6 * @inner
7 */
8export default class Sign {
9 static sign(secretKey: string, signStr: string, signMethod: string): string {
10 const signMethodMap: {
11 [key: string]: string
12 } = {
13 HmacSHA1: "sha1",
14 HmacSHA256: "sha256",
15 }
16
17 if (!signMethodMap.hasOwnProperty(signMethod)) {
18 throw new TencentCloudSDKHttpException(
19 "signMethod invalid, signMethod only support (HmacSHA1, HmacSHA256)"
20 )
21 }
22 const hmac = crypto.createHmac(signMethodMap[signMethod], secretKey || "")
23 return hmac.update(Buffer.from(signStr, "utf8")).digest("base64")
24 }
25
26 static sign3({
27 method = "POST",
28 url = "",
29 payload,
30 timestamp,
31 service,
32 secretId,
33 secretKey,
34 multipart,
35 boundary,
36 }: {
37 method?: string
38 url?: string
39 payload: any
40 timestamp: number
41 service: string
42 secretId: string
43 secretKey: string
44 multipart: boolean
45 boundary: string
46 }): string {
47 const urlObj = new URL(url)
48
49 // 通用头部
50 let headers = ""
51 let signedHeaders = ""
52 if (method === "GET") {
53 signedHeaders = "content-type"
54 headers = "content-type:application/x-www-form-urlencoded\n"
55 } else if (method === "POST") {
56 signedHeaders = "content-type"
57 if (multipart) {
58 headers = `content-type:multipart/form-data; boundary=${boundary}\n`
59 } else {
60 headers = "content-type:application/json\n"
61 }
62 }
63 headers += `host:${urlObj.hostname}\n`
64 signedHeaders += ";host"
65
66 const path = urlObj.pathname
67 const querystring = urlObj.search.slice(1)
68
69 let payload_hash = ""
70 if (multipart) {
71 const hash = crypto.createHash("sha256")
72 hash.update(`--${boundary}`)
73 for (const key in payload) {
74 const content = payload[key]
75 if (Buffer.isBuffer(content)) {
76 hash.update(
77 `\r\nContent-Disposition: form-data; name="${key}"\r\nContent-Type: application/octet-stream\r\n\r\n`
78 )
79 hash.update(content)
80 hash.update("\r\n")
81 } else if (typeof content === "string") {
82 hash.update(`\r\nContent-Disposition: form-data; name="${key}"\r\n\r\n`)
83 hash.update(`${content}\r\n`)
84 }
85 hash.update(`--${boundary}`)
86 }
87 hash.update(`--\r\n`)
88 payload_hash = hash.digest("hex")
89 } else {
90 payload_hash = payload ? getHash(JSON.stringify(payload)) : getHash("")
91 }
92
93 const canonicalRequest =
94 method +
95 "\n" +
96 path +
97 "\n" +
98 querystring +
99 "\n" +
100 headers +
101 "\n" +
102 signedHeaders +
103 "\n" +
104 payload_hash
105 const date = getDate(timestamp)
106
107 const StringToSign =
108 "TC3-HMAC-SHA256" +
109 "\n" +
110 timestamp +
111 "\n" +
112 `${date}/${service}/tc3_request` +
113 "\n" +
114 getHash(canonicalRequest)
115
116 const kDate = sha256(date, "TC3" + secretKey)
117 const kService = sha256(service, kDate)
118 const kSigning = sha256("tc3_request", kService)
119 const signature = sha256(StringToSign, kSigning, "hex")
120
121 return `TC3-HMAC-SHA256 Credential=${secretId}/${date}/${service}/tc3_request, SignedHeaders=${signedHeaders}, Signature=${signature}`
122 }
123}
124
125function sha256(message: string, secret = "", encoding?: string): string {
126 const hmac = crypto.createHmac("sha256", secret)
127 return hmac.update(message).digest(encoding as any)
128}
129
130function getHash(message: string, encoding = "hex"): string {
131 const hash = crypto.createHash("sha256")
132 return hash.update(message).digest(encoding as any)
133}
134
135function getDate(timestamp: number): string {
136 const date = new Date(timestamp * 1000)
137 const year = date.getUTCFullYear()
138 const month = ("0" + (date.getUTCMonth() + 1)).slice(-2)
139 const day = ("0" + date.getUTCDate()).slice(-2)
140 return `${year}-${month}-${day}`
141}