"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
var fs = _interopRequireWildcard(require("fs/promises"), true);
var http = _interopRequireWildcard(require("http"), true);
var https = _interopRequireWildcard(require("https"), true);
var _url = require("url");
var _CredentialProvider = require("./CredentialProvider.js");
var _Credentials = require("./Credentials.js");
var _helper = require("./internal/helper.js");
var _request = require("./internal/request.js");
var _response = require("./internal/response.js");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
class IamAwsProvider extends _CredentialProvider.CredentialProvider {
  accessExpiresAt = '';
  constructor({
    customEndpoint = undefined,
    transportAgent = undefined
  }) {
    super({
      accessKey: '',
      secretKey: ''
    });
    this.customEndpoint = customEndpoint;
    this.transportAgent = transportAgent;

    /**
     * Internal Tracking variables
     */
    this._credentials = null;
  }
  async getCredentials() {
    if (!this._credentials || this.isAboutToExpire()) {
      this._credentials = await this.fetchCredentials();
    }
    return this._credentials;
  }
  async fetchCredentials() {
    try {
      // check for IRSA (https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html)
      const tokenFile = process.env.AWS_WEB_IDENTITY_TOKEN_FILE;
      if (tokenFile) {
        return await this.fetchCredentialsUsingTokenFile(tokenFile);
      }

      // try with IAM role for EC2 instances (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)
      let tokenHeader = 'Authorization';
      let token = process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;
      const relativeUri = process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI;
      const fullUri = process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI;
      let url;
      if (relativeUri) {
        url = new _url.URL(relativeUri, 'http://169.254.170.2');
      } else if (fullUri) {
        url = new _url.URL(fullUri);
      } else {
        token = await this.fetchImdsToken();
        tokenHeader = 'X-aws-ec2-metadata-token';
        url = await this.getIamRoleNamedUrl(token);
      }
      return this.requestCredentials(url, tokenHeader, token);
    } catch (err) {
      throw new Error(`Failed to get Credentials: ${err}`, {
        cause: err
      });
    }
  }
  async fetchCredentialsUsingTokenFile(tokenFile) {
    const token = await fs.readFile(tokenFile, {
      encoding: 'utf8'
    });
    const region = process.env.AWS_REGION;
    const stsEndpoint = new _url.URL(region ? `https://sts.${region}.amazonaws.com` : 'https://sts.amazonaws.com');
    const hostValue = stsEndpoint.hostname;
    const portValue = stsEndpoint.port;
    const qryParams = new _url.URLSearchParams({
      Action: 'AssumeRoleWithWebIdentity',
      Version: '2011-06-15'
    });
    const roleArn = process.env.AWS_ROLE_ARN;
    if (roleArn) {
      qryParams.set('RoleArn', roleArn);
      const roleSessionName = process.env.AWS_ROLE_SESSION_NAME;
      qryParams.set('RoleSessionName', roleSessionName ? roleSessionName : Date.now().toString());
    }
    qryParams.set('WebIdentityToken', token);
    qryParams.sort();
    const requestOptions = {
      hostname: hostValue,
      port: portValue,
      path: `${stsEndpoint.pathname}?${qryParams.toString()}`,
      protocol: stsEndpoint.protocol,
      method: 'POST',
      headers: {},
      agent: this.transportAgent
    };
    const transport = stsEndpoint.protocol === 'http:' ? http : https;
    const res = await (0, _request.request)(transport, requestOptions, null);
    const body = await (0, _response.readAsString)(res);
    const assumeRoleResponse = (0, _helper.parseXml)(body);
    const creds = assumeRoleResponse.AssumeRoleWithWebIdentityResponse.AssumeRoleWithWebIdentityResult.Credentials;
    this.accessExpiresAt = creds.Expiration;
    return new _Credentials.Credentials({
      accessKey: creds.AccessKeyId,
      secretKey: creds.SecretAccessKey,
      sessionToken: creds.SessionToken
    });
  }
  async fetchImdsToken() {
    const endpoint = this.customEndpoint ? this.customEndpoint : 'http://169.254.169.254';
    const url = new _url.URL('/latest/api/token', endpoint);
    const requestOptions = {
      hostname: url.hostname,
      port: url.port,
      path: `${url.pathname}${url.search}`,
      protocol: url.protocol,
      method: 'PUT',
      headers: {
        'X-aws-ec2-metadata-token-ttl-seconds': '21600'
      },
      agent: this.transportAgent
    };
    const transport = url.protocol === 'http:' ? http : https;
    const res = await (0, _request.request)(transport, requestOptions, null);
    return await (0, _response.readAsString)(res);
  }
  async getIamRoleNamedUrl(token) {
    const endpoint = this.customEndpoint ? this.customEndpoint : 'http://169.254.169.254';
    const url = new _url.URL('latest/meta-data/iam/security-credentials/', endpoint);
    const roleName = await this.getIamRoleName(url, token);
    return new _url.URL(`${url.pathname}/${encodeURIComponent(roleName)}`, url.origin);
  }
  async getIamRoleName(url, token) {
    const requestOptions = {
      hostname: url.hostname,
      port: url.port,
      path: `${url.pathname}${url.search}`,
      protocol: url.protocol,
      method: 'GET',
      headers: {
        'X-aws-ec2-metadata-token': token
      },
      agent: this.transportAgent
    };
    const transport = url.protocol === 'http:' ? http : https;
    const res = await (0, _request.request)(transport, requestOptions, null);
    const body = await (0, _response.readAsString)(res);
    const roleNames = body.split(/\r\n|[\n\r\u2028\u2029]/);
    if (roleNames.length === 0) {
      throw new Error(`No IAM roles attached to EC2 service ${url}`);
    }
    return roleNames[0];
  }
  async requestCredentials(url, tokenHeader, token) {
    const headers = {};
    if (token) {
      headers[tokenHeader] = token;
    }
    const requestOptions = {
      hostname: url.hostname,
      port: url.port,
      path: `${url.pathname}${url.search}`,
      protocol: url.protocol,
      method: 'GET',
      headers: headers,
      agent: this.transportAgent
    };
    const transport = url.protocol === 'http:' ? http : https;
    const res = await (0, _request.request)(transport, requestOptions, null);
    const body = await (0, _response.readAsString)(res);
    const ecsCredentials = JSON.parse(body);
    if (!ecsCredentials.Code || ecsCredentials.Code != 'Success') {
      throw new Error(`${url} failed with code ${ecsCredentials.Code} and message ${ecsCredentials.Message}`);
    }
    this.accessExpiresAt = ecsCredentials.Expiration;
    return new _Credentials.Credentials({
      accessKey: ecsCredentials.AccessKeyID,
      secretKey: ecsCredentials.SecretAccessKey,
      sessionToken: ecsCredentials.Token
    });
  }
  isAboutToExpire() {
    const expiresAt = new Date(this.accessExpiresAt);
    const provisionalExpiry = new Date(Date.now() + 1000 * 10); // 10 seconds leeway
    return provisionalExpiry > expiresAt;
  }
}

// deprecated default export, please use named exports.
// keep for backward compatibility.
// eslint-disable-next-line import/no-default-export
exports.IamAwsProvider = IamAwsProvider;
var _default = IamAwsProvider;
exports.default = _default;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,[encoded data, 22932 characters]