import TencentCloudSDKHttpException from "./exception/tencent_cloud_sdk_exception" import * as crypto from "crypto" import { URL } from "url" /** * @inner */ export default class Sign { static sign(secretKey: string, signStr: string, signMethod: string): string { const signMethodMap: { [key: string]: string } = { HmacSHA1: "sha1", HmacSHA256: "sha256", } if (!signMethodMap.hasOwnProperty(signMethod)) { throw new TencentCloudSDKHttpException( "signMethod invalid, signMethod only support (HmacSHA1, HmacSHA256)" ) } const hmac = crypto.createHmac(signMethodMap[signMethod], secretKey || "") return hmac.update(Buffer.from(signStr, "utf8")).digest("base64") } static sign3({ method = "POST", url = "", payload, timestamp, service, secretId, secretKey, multipart, boundary, }: { method?: string url?: string payload: any timestamp: number service: string secretId: string secretKey: string multipart: boolean boundary: string }): string { const urlObj = new URL(url) // 通用头部 let headers = "" let signedHeaders = "" if (method === "GET") { signedHeaders = "content-type" headers = "content-type:application/x-www-form-urlencoded\n" } else if (method === "POST") { signedHeaders = "content-type" if (multipart) { headers = `content-type:multipart/form-data; boundary=${boundary}\n` } else { headers = "content-type:application/json\n" } } headers += `host:${urlObj.hostname}\n` signedHeaders += ";host" const path = urlObj.pathname const querystring = urlObj.search.slice(1) let payload_hash = "" if (multipart) { const hash = crypto.createHash("sha256") hash.update(`--${boundary}`) for (const key in payload) { const content = payload[key] if (Buffer.isBuffer(content)) { hash.update( `\r\nContent-Disposition: form-data; name="${key}"\r\nContent-Type: application/octet-stream\r\n\r\n` ) hash.update(content) hash.update("\r\n") } else if (typeof content === "string") { hash.update(`\r\nContent-Disposition: form-data; name="${key}"\r\n\r\n`) hash.update(`${content}\r\n`) } hash.update(`--${boundary}`) } hash.update(`--\r\n`) payload_hash = hash.digest("hex") } else { payload_hash = payload ? getHash(JSON.stringify(payload)) : getHash("") } const canonicalRequest = method + "\n" + path + "\n" + querystring + "\n" + headers + "\n" + signedHeaders + "\n" + payload_hash const date = getDate(timestamp) const StringToSign = "TC3-HMAC-SHA256" + "\n" + timestamp + "\n" + `${date}/${service}/tc3_request` + "\n" + getHash(canonicalRequest) const kDate = sha256(date, "TC3" + secretKey) const kService = sha256(service, kDate) const kSigning = sha256("tc3_request", kService) const signature = sha256(StringToSign, kSigning, "hex") return `TC3-HMAC-SHA256 Credential=${secretId}/${date}/${service}/tc3_request, SignedHeaders=${signedHeaders}, Signature=${signature}` } } function sha256(message: string, secret = "", encoding?: string): string { const hmac = crypto.createHmac("sha256", secret) return hmac.update(message).digest(encoding as any) } function getHash(message: string, encoding = "hex"): string { const hash = crypto.createHash("sha256") return hash.update(message).digest(encoding as any) } function getDate(timestamp: number): string { const date = new Date(timestamp * 1000) const year = date.getUTCFullYear() const month = ("0" + (date.getUTCMonth() + 1)).slice(-2) const day = ("0" + date.getUTCDate()).slice(-2) return `${year}-${month}-${day}` }