|                                                                                                                                                            |  | const debug = require('debug')('ali-oss:sts');const crypto = require('crypto');const querystring = require('querystring');const copy = require('copy-to');const AgentKeepalive = require('agentkeepalive');const is = require('is-type-of');const ms = require('humanize-ms');const urllib = require('urllib');
const globalHttpAgent = new AgentKeepalive();
function STS(options) {  if (!(this instanceof STS)) {    return new STS(options);  }
  if (!options || !options.accessKeyId || !options.accessKeySecret) {    throw new Error('require accessKeyId, accessKeySecret');  }
  this.options = {    endpoint: options.endpoint || 'https://sts.aliyuncs.com',    format: 'JSON',    apiVersion: '2015-04-01',    sigMethod: 'HMAC-SHA1',    sigVersion: '1.0',    timeout: '60s'  };  copy(options).to(this.options);
  // support custom agent and urllib client
  if (this.options.urllib) {    this.urllib = this.options.urllib;  } else {    this.urllib = urllib;    this.agent = this.options.agent || globalHttpAgent;  }}
module.exports = STS;
const proto = STS.prototype;
/** * STS opertaions */
proto.assumeRole = async function assumeRole(role, policy, expiration, session, options) {  const opts = this.options;  const params = {    Action: 'AssumeRole',    RoleArn: role,    RoleSessionName: session || 'app',    DurationSeconds: expiration || 3600,
    Format: opts.format,    Version: opts.apiVersion,    AccessKeyId: opts.accessKeyId,    SignatureMethod: opts.sigMethod,    SignatureVersion: opts.sigVersion,    SignatureNonce: Math.random(),    Timestamp: new Date().toISOString()  };
  if (policy) {    let policyStr;    if (is.string(policy)) {      try {        policyStr = JSON.stringify(JSON.parse(policy));      } catch (err) {        throw new Error(`Policy string is not a valid JSON: ${err.message}`);      }    } else {      policyStr = JSON.stringify(policy);    }    params.Policy = policyStr;  }
  const signature = this._getSignature('POST', params, opts.accessKeySecret);  params.Signature = signature;
  const reqUrl = opts.endpoint;  const reqParams = {    agent: this.agent,    timeout: ms((options && options.timeout) || opts.timeout),    method: 'POST',    content: querystring.stringify(params),    headers: {      'Content-Type': 'application/x-www-form-urlencoded'    },    ctx: options && options.ctx  };
  const result = await this.urllib.request(reqUrl, reqParams);  debug('response %s %s, got %s, headers: %j', reqParams.method, reqUrl, result.status, result.headers);
  if (Math.floor(result.status / 100) !== 2) {    const err = await this._requestError(result);    err.params = reqParams;    throw err;  }  result.data = JSON.parse(result.data);
  return {    res: result.res,    credentials: result.data.Credentials  };};
proto._requestError = async function _requestError(result) {  const err = new Error();  err.status = result.status;
  try {    const resp = (await JSON.parse(result.data)) || {};    err.code = resp.Code;    err.message = `${resp.Code}: ${resp.Message}`;    err.requestId = resp.RequestId;  } catch (e) {    err.message = `UnknownError: ${String(result.data)}`;  }
  return err;};
proto._getSignature = function _getSignature(method, params, key) {  const that = this;  const canoQuery = Object.keys(params)    .sort()    .map(k => `${that._escape(k)}=${that._escape(params[k])}`)    .join('&');
  const stringToSign = `${method.toUpperCase()}&${this._escape('/')}&${this._escape(canoQuery)}`;
  debug('string to sign: %s', stringToSign);
  let signature = crypto.createHmac('sha1', `${key}&`);  signature = signature.update(stringToSign).digest('base64');
  debug('signature: %s', signature);
  return signature;};
/** * Since `encodeURIComponent` doesn't encode '*', which causes * 'SignatureDoesNotMatch'. We need do it ourselves. */proto._escape = function _escape(str) {  return encodeURIComponent(str)    .replace(/!/g, '%21')    .replace(/'/g, '%27')    .replace(/\(/g, '%28')    .replace(/\)/g, '%29')    .replace(/\*/g, '%2A');};
 |