ts/src/utils.ts (661 lines of code) (raw):

// This file is auto-generated, don't edit it /** * This is for OpenApi Util */ import * as $tea from '@alicloud/tea-typescript'; import * as $dara from '@darabonba/typescript'; import Credential from '@alicloud/credentials'; import { Readable } from 'stream'; import querystring from 'querystring'; import crypto from 'crypto'; import os from 'os'; const PEM_BEGIN = "-----BEGIN PRIVATE KEY-----\n"; const PEM_END = "\n-----END PRIVATE KEY-----"; const DEFAULT_USER_AGENT = `AlibabaCloud (${os.platform()}; ${os.arch()}) Node.js/${process.version} Core/1.0.1 TeaDSL/2`; export class GlobalParameters extends $tea.Model { headers?: { [key: string]: string }; queries?: { [key: string]: string }; static names(): { [key: string]: string } { return { headers: 'headers', queries: 'queries', }; } static types(): { [key: string]: any } { return { headers: { 'type': 'map', 'keyType': 'string', 'valueType': 'string' }, queries: { 'type': 'map', 'keyType': 'string', 'valueType': 'string' }, }; } constructor(map?: { [key: string]: any }) { super(map); } } /** * @remarks * Model for initing client */ export class Config extends $tea.Model { /** * @remarks * accesskey id */ accessKeyId?: string; /** * @remarks * accesskey secret */ accessKeySecret?: string; /** * @remarks * security token */ securityToken?: string; /** * @remarks * bearer token * * @example * the-bearer-token */ bearerToken?: string; /** * @remarks * http protocol * * @example * http */ protocol?: string; /** * @remarks * http method * * @example * GET */ method?: string; /** * @remarks * region id * * @example * cn-hangzhou */ regionId?: string; /** * @remarks * read timeout * * @example * 10 */ readTimeout?: number; /** * @remarks * connect timeout * * @example * 10 */ connectTimeout?: number; /** * @remarks * http proxy * * @example * http://localhost */ httpProxy?: string; /** * @remarks * https proxy * * @example * https://localhost */ httpsProxy?: string; /** * @remarks * credential */ credential?: Credential; /** * @remarks * endpoint * * @example * cs.aliyuncs.com */ endpoint?: string; /** * @remarks * proxy white list * * @example * http://localhost */ noProxy?: string; /** * @remarks * max idle conns * * @example * 3 */ maxIdleConns?: number; /** * @remarks * network for endpoint * * @example * public */ network?: string; /** * @remarks * user agent * * @example * Alibabacloud/1 */ userAgent?: string; /** * @remarks * suffix for endpoint * * @example * aliyun */ suffix?: string; /** * @remarks * socks5 proxy */ socks5Proxy?: string; /** * @remarks * socks5 network * * @example * TCP */ socks5NetWork?: string; /** * @remarks * endpoint type * * @example * internal */ endpointType?: string; /** * @remarks * OpenPlatform endpoint * * @example * openplatform.aliyuncs.com */ openPlatformEndpoint?: string; /** * @remarks * credential type * * @example * access_key * * @deprecated */ type?: string; /** * @remarks * Signature Version * * @example * v1 */ signatureVersion?: string; /** * @remarks * Signature Algorithm * * @example * ACS3-HMAC-SHA256 */ signatureAlgorithm?: string; /** * @remarks * Global Parameters */ globalParameters?: GlobalParameters; /** * @remarks * privite key for client certificate * * @example * MIIEvQ */ key?: string; /** * @remarks * client certificate * * @example * -----BEGIN CERTIFICATE----- * xxx-----END CERTIFICATE----- */ cert?: string; /** * @remarks * server certificate * * @example * -----BEGIN CERTIFICATE----- * xxx-----END CERTIFICATE----- */ ca?: string; /** * @remarks * disable HTTP/2 * * @example * false */ disableHttp2?: boolean; tlsMinVersion?: string; /** * @remarks * retry options */ retryOptions?: $dara.RetryOptions; static names(): { [key: string]: string } { return { accessKeyId: 'accessKeyId', accessKeySecret: 'accessKeySecret', securityToken: 'securityToken', bearerToken: 'bearerToken', protocol: 'protocol', method: 'method', regionId: 'regionId', readTimeout: 'readTimeout', connectTimeout: 'connectTimeout', httpProxy: 'httpProxy', httpsProxy: 'httpsProxy', credential: 'credential', endpoint: 'endpoint', noProxy: 'noProxy', maxIdleConns: 'maxIdleConns', network: 'network', userAgent: 'userAgent', suffix: 'suffix', socks5Proxy: 'socks5Proxy', socks5NetWork: 'socks5NetWork', endpointType: 'endpointType', openPlatformEndpoint: 'openPlatformEndpoint', type: 'type', signatureVersion: 'signatureVersion', signatureAlgorithm: 'signatureAlgorithm', globalParameters: 'globalParameters', key: 'key', cert: 'cert', ca: 'ca', disableHttp2: 'disableHttp2', tlsMinVersion: 'tlsMinVersion', retryOptions: 'retryOptions', }; } static types(): { [key: string]: any } { return { accessKeyId: 'string', accessKeySecret: 'string', securityToken: 'string', bearerToken: 'string', protocol: 'string', method: 'string', regionId: 'string', readTimeout: 'number', connectTimeout: 'number', httpProxy: 'string', httpsProxy: 'string', credential: Credential, endpoint: 'string', noProxy: 'string', maxIdleConns: 'number', network: 'string', userAgent: 'string', suffix: 'string', socks5Proxy: 'string', socks5NetWork: 'string', endpointType: 'string', openPlatformEndpoint: 'string', type: 'string', signatureVersion: 'string', signatureAlgorithm: 'string', globalParameters: GlobalParameters, key: 'string', cert: 'string', ca: 'string', disableHttp2: 'boolean', tlsMinVersion: 'string', retryOptions: $dara.RetryOptions, }; } constructor(map?: { [key: string]: any }) { super(map); } } export class OpenApiRequest extends $tea.Model { headers?: { [key: string]: string }; query?: { [key: string]: string }; body?: any; stream?: Readable; hostMap?: { [key: string]: string }; endpointOverride?: string; static names(): { [key: string]: string } { return { headers: 'headers', query: 'query', body: 'body', stream: 'stream', hostMap: 'hostMap', endpointOverride: 'endpointOverride', }; } static types(): { [key: string]: any } { return { headers: { 'type': 'map', 'keyType': 'string', 'valueType': 'string' }, query: { 'type': 'map', 'keyType': 'string', 'valueType': 'string' }, body: 'any', stream: 'Readable', hostMap: { 'type': 'map', 'keyType': 'string', 'valueType': 'string' }, endpointOverride: 'string', }; } constructor(map?: { [key: string]: any }) { super(map); } } export class Params extends $tea.Model { action: string; version: string; protocol: string; pathname: string; method: string; authType: string; bodyType: string; reqBodyType: string; style?: string; static names(): { [key: string]: string } { return { action: 'action', version: 'version', protocol: 'protocol', pathname: 'pathname', method: 'method', authType: 'authType', bodyType: 'bodyType', reqBodyType: 'reqBodyType', style: 'style', }; } static types(): { [key: string]: any } { return { action: 'string', version: 'string', protocol: 'string', pathname: 'string', method: 'string', authType: 'string', bodyType: 'string', reqBodyType: 'string', style: 'string', }; } constructor(map?: { [key: string]: any }) { super(map); } } function replaceRepeatList(target: { [key: string]: string }, repeat: any[], prefix: string) { if (prefix) { prefix = prefix + '.'; } for (var i = 0; i < repeat.length; i++) { var item = repeat[i]; let key = prefix + (i + 1); if (typeof item === 'undefined' || item == null) { continue; } if (Array.isArray(item)) { replaceRepeatList(target, item, key); } else if (item instanceof Object) { flatMap(target, item, key); } else { target[key] = item.toString(); } } } function flatMap(target: { [key: string]: any }, params: { [key: string]: any }, prefix: string = '') { if (prefix) { prefix = prefix + '.'; } params = toMap(params); let keys = Object.keys(params); for (let i = 0; i < keys.length; i++) { let key = keys[i]; let value = params[key]; key = prefix + key; if (typeof value === 'undefined' || value == null) { continue; } if (Array.isArray(value)) { replaceRepeatList(target, value, key); } else if (value instanceof Object) { flatMap(target, value, key); } else { target[key] = value.toString(); } } return target; } function filter(value: string): string { return value.replace(/[\t\n\r\f]/g, ' '); } function getCanonicalizedHeaders(headers: { [key: string]: string }): string { const prefix = 'x-acs-'; const keys = Object.keys(headers); const canonicalizedKeys = []; for (let i = 0; i < keys.length; i++) { const key = keys[i]; if (key.startsWith(prefix)) { canonicalizedKeys.push(key); } } canonicalizedKeys.sort(); var result = ''; for (let i = 0; i < canonicalizedKeys.length; i++) { const key = canonicalizedKeys[i]; result += `${key}:${filter(headers[key]).trim()}\n`; } return result; } function getCanonicalizedResource(uriPattern: string, query: { [key: string]: string }): string { const keys = !query ? [] : Object.keys(query).sort(); if (keys.length === 0) { return uriPattern; } var result = []; for (var i = 0; i < keys.length; i++) { const key = keys[i]; result.push(`${key}=${query[key]}`); } return `${uriPattern}?${result.join('&')}`; } function getAuthorizationQueryString(query: { [key: string]: string }): string { let canonicalQueryArray = []; const keys = !query ? [] : Object.keys(query).sort(); for (let i = 0; i < keys.length; i++) { const key = keys[i]; let param = key + '=' if (typeof query[key] !== 'undefined' && query[key] !== null) { param = param + encode(query[key]) } canonicalQueryArray.push(param) } return canonicalQueryArray.join('&'); } function getAuthorizationHeaders(header: { [key: string]: string }): {} { let canonicalheaders = ""; let tmp = {}; const keys = !header ? [] : Object.keys(header); for (let i = 0; i < keys.length; i++) { const key = keys[i]; const lowerKey = keys[i].toLowerCase(); if (lowerKey.startsWith("x-acs-") || lowerKey === "host" || lowerKey === "content-type") { if (tmp[lowerKey]) { tmp[lowerKey].push((header[key] || "").trim()); } else { tmp[lowerKey] = [(header[key] || "").trim()]; } } } var hsKeys = Object.keys(tmp).sort(); for (let i = 0; i < hsKeys.length; i++) { const hsKey = hsKeys[i]; let listSort = tmp[hsKey].sort(); canonicalheaders += `${hsKey}:${listSort.join(",")}\n`; } return { canonicalheaders, hsKeys }; } function encode(str: string) { var result = encodeURIComponent(str); return result.replace(/!/g, '%21') .replace(/'/g, '%27') .replace(/\(/g, '%28') .replace(/\)/g, '%29') .replace(/\*/g, '%2A'); } function normalize(params: { [key: string]: any }) { var list = []; var flated: { [key: string]: string } = {}; flatMap(flated, params); var keys = Object.keys(flated).sort(); for (let i = 0; i < keys.length; i++) { var key = keys[i]; var value = flated[key]; list.push([encode(key), encode(value)]); } return list; } function canonicalize(normalized: any[]) { var fields = []; for (var i = 0; i < normalized.length; i++) { var [key, value] = normalized[i]; fields.push(key + '=' + value); } return fields.join('&'); } function isModelClass(t: any): boolean { if (!t) { return false; } return typeof t.types === 'function' && typeof t.names === 'function'; } function isObjectOrArray(t: any): boolean { return Array.isArray(t) || (t instanceof Object && typeof t !== 'function'); } function getTimeLeft(rateLimit: string | null): number | null { if (rateLimit) { const pairs = rateLimit.split(','); for (const pair of pairs) { const kv = pair.split(':'); if (kv.length === 2) { const key = kv[0].trim(); const value = kv[1].trim(); if (key === 'TimeLeft') { const timeLeftValue = parseInt(value, 10); if (isNaN(timeLeftValue)) { return null; } return timeLeftValue; } } } } return null; } function toMap(input: any) { if (!isObjectOrArray(input)) { return null; } else if (input instanceof $tea.Model) { return $tea.toMap(input); } else if (input && input.toMap && typeof input.toMap === 'function') { // 解决跨版本 Model 不互认的问题 return input.toMap(); } else if (Array.isArray(input)) { const result = []; input.forEach((value) => { if (isObjectOrArray(value)) { result.push(toMap(value)); } else { result.push(value); } }); return result; } else if (input instanceof Object) { const result = {}; Object.entries(input).forEach(([key, value]) => { if (isObjectOrArray(value)) { result[key] = toMap(value); } else { result[key] = value; } }); return result; } } export default class Client { /** * Convert all params of body other than type of readable into content * @param body source Model * @param content target Model * @return void */ static convert(input: $tea.Model, output: $tea.Model): void { if (!output) { return; } let inputModel = Object.assign({}, input); let constructor = <any>output.constructor; let types = constructor.types(); // let constructor = <any>output.constructor; for (let key of Object.keys(constructor.names())) { if (inputModel[key] !== null && inputModel[key] !== undefined) { if (isModelClass(types[key])) { output[key] = new types[key](output[key]); Client.convert(inputModel[key], output[key]); } else if (types[key] && types[key].type === 'array') { output[key] = inputModel[key].map(function (d) { if (isModelClass(types[key].itemType)) { var item = new types[key].itemType({}); Client.convert(d, item); return item; } return d; }); } else if (types[key] && types[key].type === 'map') { output[key] = {}; Object.keys(inputModel[key]).map(function (d) { if (isModelClass(types[key].valueType)) { var item = new types[key].valueType({}); Client.convert(inputModel[key][d], item); output[key][d] = item; } else { output[key][d] = inputModel[key][d]; } }); } else { output[key] = inputModel[key]; } } } } /** * If endpointType is internal, use internal endpoint * If serverUse is true and endpointType is accelerate, use accelerate endpoint * Default return endpoint * @param serverUse whether use accelerate endpoint * @param endpointType value must be internal or accelerate * @return the final endpoint */ static getEndpoint(endpoint: string, serverUse: boolean, endpointType: string): string { if (endpointType == "internal") { let strs = endpoint.split("."); strs[0] += "-internal"; endpoint = strs.join(".") } if (serverUse && endpointType == "accelerate") { return "oss-accelerate.aliyuncs.com" } return endpoint } /** * Get throttling param * @param the response headers * @return time left */ static getThrottlingTimeLeft(headers: {[key: string ]: string}): number { const rateLimitForUserApi = headers["x-ratelimit-user-api"]; const rateLimitForUser = headers["x-ratelimit-user"]; const timeLeftForUserApi = getTimeLeft(rateLimitForUserApi); const timeLeftForUser = getTimeLeft(rateLimitForUser); if (timeLeftForUserApi > timeLeftForUser) { return timeLeftForUserApi; } else { return timeLeftForUser; } } /** * Hash the raw data with signatureAlgorithm * @param raw hashing data * @param signatureAlgorithm the autograph method * @return hashed bytes */ static hash(raw: Buffer, signatureAlgorithm: string): Buffer { if (signatureAlgorithm === "ACS3-HMAC-SHA256" || signatureAlgorithm === "ACS3-RSA-SHA256") { const obj = crypto.createHash('sha256'); obj.update(raw); return obj.digest(); } else if (signatureAlgorithm == "ACS3-HMAC-SM3") { const obj = crypto.createHash('sm3'); obj.update(raw); return obj.digest(); } } /** * Generate a nonce string * @return the nonce string */ static getNonce(): string { let counter = 0; let last; const machine = os.hostname(); const pid = process.pid; var val = Math.floor(Math.random() * 1000000000000); if (val === last) { counter++; } else { counter = 0; } last = val; var uid = `${machine}${pid}${val}${counter}`; var shasum = crypto.createHash('md5'); shasum.update(uid); return shasum.digest('hex'); } /** * Get the string to be signed according to request * @param request which contains signed messages * @return the signed string */ static getStringToSign(request: $tea.Request): string { const method = request.method; const accept = request.headers['accept']; const contentMD5 = request.headers['content-md5'] || ''; const contentType = request.headers['content-type'] || ''; const date = request.headers['date'] || ''; const header = `${method}\n${accept}\n${contentMD5}\n${contentType}\n${date}\n`; const canonicalizedHeaders = getCanonicalizedHeaders(request.headers); const canonicalizedResource = getCanonicalizedResource(request.pathname, request.query); return `${header}${canonicalizedHeaders}${canonicalizedResource}`; } /** * Get signature according to stringToSign, secret * @param stringToSign the signed string * @param secret accesskey secret * @return the signature */ static getROASignature(stringToSign: string, secret: string): string { const utf8Buff = Buffer.from(stringToSign, 'utf8'); return crypto.createHmac('sha1', secret).update(utf8Buff).digest('base64') } /** * Parse filter into a form string * @param filter object * @return the string */ static toForm(filter: {[key: string]: any}): string { if (!filter) { return ''; } let target = {}; flatMap(target, filter); return $dara.Form.toFormString(target); } /** * Get timestamp * @return the timestamp string */ static getTimestamp(): string { let date = new Date(); let YYYY = date.getUTCFullYear(); let MM =`${date.getUTCMonth() + 1}`.padStart(2, '0'); let DD =`${date.getUTCDate()}`.padStart(2, '0'); let HH =`${date.getUTCHours()}`.padStart(2, '0'); let mm =`${date.getUTCMinutes()}`.padStart(2, '0'); let ss =`${date.getUTCSeconds()}`.padStart(2, '0'); return `${YYYY}-${MM}-${DD}T${HH}:${mm}:${ss}Z`; } /** * Get UTC string * @return the UTC string */ static getDateUTCString(): string { const now = new Date(); return now.toUTCString(); } /** * Parse filter into a object which's type is map[string]string * @param filter query param * @return the object */ static query(filter: {[key: string]: any}): {[key: string ]: string} { if (!filter) { return {}; } let ret: { [key: string]: string } = {}; flatMap(ret, filter); return ret; } /** * Get signature according to signedParams, method and secret * @param signedParams params which need to be signed * @param method http method e.g. GET * @param secret AccessKeySecret * @return the signature */ static getRPCSignature(signedParams: {[key: string ]: string}, method: string, secret: string): string { var normalized = normalize(signedParams); var canonicalized = canonicalize(normalized); var stringToSign = `${method}&${encode('/')}&${encode(canonicalized)}`; const key = secret + '&'; return crypto.createHmac('sha1', key).update(stringToSign).digest('base64'); } /** * Parse array into a string with specified style * @param array the array * @param prefix the prefix string * @style specified style e.g. repeatList * @return the string */ static arrayToStringWithSpecifiedStyle(array: any, prefix: string, style: string): string { if (!array) { return ''; } if (style === 'repeatList') { let target = {}; replaceRepeatList(target, array, prefix); return querystring.stringify(target, '&&'); } else if (style === 'json') { return JSON.stringify(toMap(array)); } else if (style === 'simple') { return array.join(','); } else if (style === 'spaceDelimited') { return array.join(' '); } else if (style === 'pipeDelimited') { return array.join('|'); } else { return ''; } } static stringifyMapValue(m: { [key: string]: any }): { [key: string]: string } { if (!m) { return m; } const result: { [key: string]: string } = {}; for (const [key, value] of Object.entries(m)) { if (typeof value === 'undefined' || value === null) { continue; } result[key] = String(value); } return result; } static toArray(input: any): { [key: string]: any }[] { if (!(input instanceof Array)) { return null; } let ret = []; input.forEach((model) => { if (!model) { return; } ret.push($tea.toMap(model)); }) return ret; } static getEndpointRules(product: string, regionId: string, endpointType: string, network: string, suffix: string): string { let result; if (network && network.length && network != "public") { network = "-" + network; } else { network = ""; } suffix = suffix || ""; if (suffix.length) { suffix = "-" + suffix; } if (endpointType == "regional") { if (!regionId || !regionId.length) { throw new Error("RegionId is empty, please set a valid RegionId"); } result = `${product}${suffix}${network}.${regionId}.aliyuncs.com`; } else { result = `${product}${suffix}${network}.aliyuncs.com`; } return result; } /** * Transform input as map. */ static parseToMap(input: any): {[key: string ]: any} { return toMap(input); } /** * Get the authorization * @param request request params * @param signatureAlgorithm the autograph method * @param payload the hashed request * @param accessKey the accessKey string * @param accessKeySecret the accessKeySecret string * @return authorization string */ static getAuthorization(request: $tea.Request, signatureAlgorithm: string, payload: string, accessKey: string, accessKeySecret: string): string { const canonicalURI = (request.pathname || "").replace("+", "%20").replace("*", "%2A").replace("%7E", "~"); const method = request.method; const canonicalQueryString = getAuthorizationQueryString(request.query); const tuple = getAuthorizationHeaders(request.headers); const canonicalheaders = tuple["canonicalheaders"]; const signedHeaders = tuple["hsKeys"]; const canonicalRequest = method + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalheaders + "\n" + signedHeaders.join(";") + "\n" + payload; let raw = Buffer.from(canonicalRequest); const stringToSign = signatureAlgorithm + "\n" + Client.hash(raw, signatureAlgorithm).toString("hex"); const signature = Client.signatureMethod(accessKeySecret, stringToSign, signatureAlgorithm).toString("hex"); const auth = `${signatureAlgorithm} Credential=${accessKey},SignedHeaders=${signedHeaders.join(';')},Signature=${signature}`; return auth; } static getUserAgent(userAgent: string): string { if (!userAgent || !userAgent.length) { return DEFAULT_USER_AGENT; } return DEFAULT_USER_AGENT + " " + userAgent; } static signatureMethod(secret: string, source: string, signatureAlgorithm: string): Buffer { if (signatureAlgorithm === "ACS3-HMAC-SHA256") { const obj = crypto.createHmac('sha256', secret); obj.update(source); return obj.digest(); } else if (signatureAlgorithm === "ACS3-HMAC-SM3") { const obj = crypto.createHmac('sm3', secret); obj.update(source); return obj.digest(); } else if (signatureAlgorithm === "ACS3-RSA-SHA256") { if (!secret.startsWith(PEM_BEGIN)) { secret = PEM_BEGIN + secret; } if (!secret.endsWith(PEM_END)) { secret = secret + PEM_END; } var signerObject = crypto.createSign("RSA-SHA256"); signerObject.update(source); var signature = signerObject.sign({ key: secret, padding: crypto.constants.RSA_PKCS1_PADDING }); return signature; } } }