text: /*! firebase-admin v5.11.0 */
  "use strict";
  /*!
   * Copyright 2017 Google Inc.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  Object.defineProperty(exports, "__esModule", { value: true });
  var jwt = require("jsonwebtoken");
  var forge = require("node-forge");
  // Use untyped import syntax for Node built-ins
  var fs = require("fs");
  var os = require("os");
  var http = require("http");
  var path = require("path");
  var https = require("https");
  var error_1 = require("../utils/error");
  var GOOGLE_TOKEN_AUDIENCE = 'https://accounts.google.com/o/oauth2/token';
  var GOOGLE_AUTH_TOKEN_HOST = 'accounts.google.com';
  var GOOGLE_AUTH_TOKEN_PATH = '/o/oauth2/token';
  var GOOGLE_AUTH_TOKEN_PORT = 443;
  // NOTE: the Google Metadata Service uses HTTP over a vlan
  var GOOGLE_METADATA_SERVICE_HOST = 'metadata.google.internal';
  var GOOGLE_METADATA_SERVICE_PATH = '/computeMetadata/v1beta1/instance/service-accounts/default/token';
  var configDir = (function () {
      // Windows has a dedicated low-rights location for apps at ~/Application Data
      var sys = os.platform();
      if (sys && sys.length >= 3 && sys.substring(0, 3).toLowerCase() === 'win') {
          return process.env.APPDATA;
      }
      // On *nix the gcloud cli creates a . dir.
      return process.env.HOME && path.resolve(process.env.HOME, '.config');
  })();
  var GCLOUD_CREDENTIAL_SUFFIX = 'gcloud/application_default_credentials.json';
  var GCLOUD_CREDENTIAL_PATH = configDir && path.resolve(configDir, GCLOUD_CREDENTIAL_SUFFIX);
  var REFRESH_TOKEN_HOST = 'www.googleapis.com';
  var REFRESH_TOKEN_PORT = 443;
  var REFRESH_TOKEN_PATH = '/oauth2/v4/token';
  var ONE_HOUR_IN_SECONDS = 60 * 60;
  var JWT_ALGORITHM = 'RS256';
  function copyAttr(to, from, key, alt) {
      var tmp = from[key] || from[alt];
      if (typeof tmp !== 'undefined') {
          to[key] = tmp;
      }
  }
  var RefreshToken = /** @class */ (function () {
      function RefreshToken(json) {
          copyAttr(this, json, 'clientId', 'client_id');
          copyAttr(this, json, 'clientSecret', 'client_secret');
          copyAttr(this, json, 'refreshToken', 'refresh_token');
          copyAttr(this, json, 'type', 'type');
          var errorMessage;
          if (typeof this.clientId !== 'string' || !this.clientId) {
              errorMessage = 'Refresh token must contain a "client_id" property.';
          }
          else if (typeof this.clientSecret !== 'string' || !this.clientSecret) {
              errorMessage = 'Refresh token must contain a "client_secret" property.';
          }
          else if (typeof this.refreshToken !== 'string' || !this.refreshToken) {
              errorMessage = 'Refresh token must contain a "refresh_token" property.';
          }
          else if (typeof this.type !== 'string' || !this.type) {
              errorMessage = 'Refresh token must contain a "type" property.';
          }
          if (typeof errorMessage !== 'undefined') {
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_CREDENTIAL, errorMessage);
          }
      }
      /*
       * Tries to load a RefreshToken from a path. If the path is not present, returns null.
       * Throws if data at the path is invalid.
       */
      RefreshToken.fromPath = function (filePath) {
          var jsonString;
          try {
              jsonString = fs.readFileSync(filePath, 'utf8');
          }
          catch (ignored) {
              // Ignore errors if the file is not present, as this is sometimes an expected condition
              return null;
          }
          try {
              return new RefreshToken(JSON.parse(jsonString));
          }
          catch (error) {
              // Throw a nicely formed error message if the file contents cannot be parsed
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_CREDENTIAL, 'Failed to parse refresh token file: ' + error);
          }
      };
      return RefreshToken;
  }());
  exports.RefreshToken = RefreshToken;
  /**
   * A struct containing the properties necessary to use service-account JSON credentials.
   */
  var Certificate = /** @class */ (function () {
      function Certificate(json) {
          if (typeof json !== 'object' || json === null) {
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_CREDENTIAL, 'Certificate object must be an object.');
          }
          copyAttr(this, json, 'projectId', 'project_id');
          copyAttr(this, json, 'privateKey', 'private_key');
          copyAttr(this, json, 'clientEmail', 'client_email');
          var errorMessage;
          if (typeof this.privateKey !== 'string' || !this.privateKey) {
              errorMessage = 'Certificate object must contain a string "private_key" property.';
          }
          else if (typeof this.clientEmail !== 'string' || !this.clientEmail) {
              errorMessage = 'Certificate object must contain a string "client_email" property.';
          }
          if (typeof errorMessage !== 'undefined') {
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_CREDENTIAL, errorMessage);
          }
          try {
              forge.pki.privateKeyFromPem(this.privateKey);
          }
          catch (error) {
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_CREDENTIAL, 'Failed to parse private key: ' + error);
          }
      }
      Certificate.fromPath = function (filePath) {
          // Node bug encountered in v6.x. fs.readFileSync hangs when path is a 0 or 1.
          if (typeof filePath !== 'string') {
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_CREDENTIAL, 'Failed to parse certificate key file: TypeError: path must be a string');
          }
          try {
              return new Certificate(JSON.parse(fs.readFileSync(filePath, 'utf8')));
          }
          catch (error) {
              // Throw a nicely formed error message if the file contents cannot be parsed
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_CREDENTIAL, 'Failed to parse certificate key file: ' + error);
          }
      };
      return Certificate;
  }());
  exports.Certificate = Certificate;
  /**
   * A wrapper around the http and https request libraries to simplify & promisify JSON requests.
   * TODO(inlined): Create a type for "transit".
   */
  function requestAccessToken(transit, options, data) {
      return new Promise(function (resolve, reject) {
          var req = transit.request(options, function (res) {
              var buffers = [];
              res.on('data', function (buffer) { return buffers.push(buffer); });
              res.on('end', function () {
                  try {
                      var json = JSON.parse(Buffer.concat(buffers).toString());
                      if (json.error) {
                          var errorMessage = 'Error fetching access token: ' + json.error;
                          if (json.error_description) {
                              errorMessage += ' (' + json.error_description + ')';
                          }
                          reject(new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_CREDENTIAL, errorMessage));
                      }
                      else if (!json.access_token || !json.expires_in) {
                          reject(new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_CREDENTIAL, "Unexpected response while fetching access token: " + JSON.stringify(json)));
                      }
                      else {
                          resolve(json);
                      }
                  }
                  catch (err) {
                      reject(new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_CREDENTIAL, "Failed to parse access token response: " + err.toString()));
                  }
              });
          });
          req.on('error', reject);
          if (data) {
              req.write(data);
          }
          req.end();
      });
  }
  /**
   * Implementation of Credential that uses a service account certificate.
   */
  var CertCredential = /** @class */ (function () {
      function CertCredential(serviceAccountPathOrObject) {
          this.certificate_ = (typeof serviceAccountPathOrObject === 'string') ?
              Certificate.fromPath(serviceAccountPathOrObject) : new Certificate(serviceAccountPathOrObject);
      }
      CertCredential.prototype.getAccessToken = function () {
          var token = this.createAuthJwt_();
          var postData = 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3A' +
              'grant-type%3Ajwt-bearer&assertion=' +
              token;
          var options = {
              method: 'POST',
              host: GOOGLE_AUTH_TOKEN_HOST,
              port: GOOGLE_AUTH_TOKEN_PORT,
              path: GOOGLE_AUTH_TOKEN_PATH,
              headers: {
                  'Content-Type': 'application/x-www-form-urlencoded',
                  'Content-Length': postData.length,
              },
          };
          return requestAccessToken(https, options, postData);
      };
      CertCredential.prototype.getCertificate = function () {
          return this.certificate_;
      };
      CertCredential.prototype.createAuthJwt_ = function () {
          var claims = {
              scope: [
                  'https://www.googleapis.com/auth/cloud-platform',
                  'https://www.googleapis.com/auth/firebase.database',
                  'https://www.googleapis.com/auth/firebase.messaging',
                  'https://www.googleapis.com/auth/identitytoolkit',
                  'https://www.googleapis.com/auth/userinfo.email',
              ].join(' '),
          };
          // This method is actually synchronous so we can capture and return the buffer.
          return jwt.sign(claims, this.certificate_.privateKey, {
              audience: GOOGLE_TOKEN_AUDIENCE,
              expiresIn: ONE_HOUR_IN_SECONDS,
              issuer: this.certificate_.clientEmail,
              algorithm: JWT_ALGORITHM,
          });
      };
      return CertCredential;
  }());
  exports.CertCredential = CertCredential;
  /**
   * Implementation of Credential that gets access tokens from refresh tokens.
   */
  var RefreshTokenCredential = /** @class */ (function () {
      function RefreshTokenCredential(refreshTokenPathOrObject) {
          this.refreshToken_ = (typeof refreshTokenPathOrObject === 'string') ?
              RefreshToken.fromPath(refreshTokenPathOrObject) : new RefreshToken(refreshTokenPathOrObject);
      }
      RefreshTokenCredential.prototype.getAccessToken = function () {
          var postData = 'client_id=' + this.refreshToken_.clientId + '&' +
              'client_secret=' + this.refreshToken_.clientSecret + '&' +
              'refresh_token=' + this.refreshToken_.refreshToken + '&' +
              'grant_type=refresh_token';
          var options = {
              method: 'POST',
              host: REFRESH_TOKEN_HOST,
              port: REFRESH_TOKEN_PORT,
              path: REFRESH_TOKEN_PATH,
              headers: {
                  'Content-Type': 'application/x-www-form-urlencoded',
                  'Content-Length': postData.length,
              },
          };
          return requestAccessToken(https, options, postData);
      };
      RefreshTokenCredential.prototype.getCertificate = function () {
          return null;
      };
      return RefreshTokenCredential;
  }());
  exports.RefreshTokenCredential = RefreshTokenCredential;
  /**
   * Implementation of Credential that gets access tokens from the metadata service available
   * in the Google Cloud Platform. This authenticates the process as the default service account
   * of an App Engine instance or Google Compute Engine machine.
   */
  var MetadataServiceCredential = /** @class */ (function () {
      function MetadataServiceCredential() {
      }
      MetadataServiceCredential.prototype.getAccessToken = function () {
          var options = {
              method: 'GET',
              host: GOOGLE_METADATA_SERVICE_HOST,
              path: GOOGLE_METADATA_SERVICE_PATH,
              headers: {
                  'Content-Length': 0,
              },
          };
          return requestAccessToken(http, options);
      };
      MetadataServiceCredential.prototype.getCertificate = function () {
          return null;
      };
      return MetadataServiceCredential;
  }());
  exports.MetadataServiceCredential = MetadataServiceCredential;
  /**
   * ApplicationDefaultCredential implements the process for loading credentials as
   * described in https://developers.google.com/identity/protocols/application-default-credentials
   */
  var ApplicationDefaultCredential = /** @class */ (function () {
      function ApplicationDefaultCredential() {
          if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
              var serviceAccount = Certificate.fromPath(process.env.GOOGLE_APPLICATION_CREDENTIALS);
              this.credential_ = new CertCredential(serviceAccount);
              return;
          }
          // It is OK to not have this file. If it is present, it must be valid.
          var refreshToken = RefreshToken.fromPath(GCLOUD_CREDENTIAL_PATH);
          if (refreshToken) {
              this.credential_ = new RefreshTokenCredential(refreshToken);
              return;
          }
          this.credential_ = new MetadataServiceCredential();
      }
      ApplicationDefaultCredential.prototype.getAccessToken = function () {
          return this.credential_.getAccessToken();
      };
      ApplicationDefaultCredential.prototype.getCertificate = function () {
          return this.credential_.getCertificate();
      };
      // Used in testing to verify we are delegating to the correct implementation.
      ApplicationDefaultCredential.prototype.getCredential = function () {
          return this.credential_;
      };
      return ApplicationDefaultCredential;
  }());
  exports.ApplicationDefaultCredential = ApplicationDefaultCredential;
  