text: "use strict";
  
  exports.__esModule = true;
  exports["default"] = void 0;
  
  var _buffer = require("buffer");
  
  var _core = _interopRequireDefault(require("crypto-js/core"));
  
  var _libTypedarrays = _interopRequireDefault(require("crypto-js/lib-typedarrays"));
  
  var _encBase = _interopRequireDefault(require("crypto-js/enc-base64"));
  
  var _hmacSha = _interopRequireDefault(require("crypto-js/hmac-sha256"));
  
  var _BigInteger = _interopRequireDefault(require("./BigInteger"));
  
  var _AuthenticationHelper = _interopRequireDefault(require("./AuthenticationHelper"));
  
  var _CognitoAccessToken = _interopRequireDefault(require("./CognitoAccessToken"));
  
  var _CognitoIdToken = _interopRequireDefault(require("./CognitoIdToken"));
  
  var _CognitoRefreshToken = _interopRequireDefault(require("./CognitoRefreshToken"));
  
  var _CognitoUserSession = _interopRequireDefault(require("./CognitoUserSession"));
  
  var _DateHelper = _interopRequireDefault(require("./DateHelper"));
  
  var _CognitoUserAttribute = _interopRequireDefault(require("./CognitoUserAttribute"));
  
  var _StorageHelper = _interopRequireDefault(require("./StorageHelper"));
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  
  /*!
   * Copyright 2016 Amazon.com,
   * Inc. or its affiliates. All Rights Reserved.
   *
   * Licensed under the Amazon Software License (the "License").
   * You may not use this file except in compliance with the
   * License. A copy of the License is located at
   *
   *     http://aws.amazon.com/asl/
   *
   * or in the "license" file accompanying this file. This file is
   * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   * CONDITIONS OF ANY KIND, express or implied. See the License
   * for the specific language governing permissions and
   * limitations under the License.
   */
  // necessary for crypto js
  
  /**
   * @callback nodeCallback
   * @template T result
   * @param {*} err The operation failure reason, or null.
   * @param {T} result The operation result.
   */
  
  /**
   * @callback onFailure
   * @param {*} err Failure reason.
   */
  
  /**
   * @callback onSuccess
   * @template T result
   * @param {T} result The operation result.
   */
  
  /**
   * @callback mfaRequired
   * @param {*} details MFA challenge details.
   */
  
  /**
   * @callback customChallenge
   * @param {*} details Custom challenge details.
   */
  
  /**
   * @callback inputVerificationCode
   * @param {*} data Server response.
   */
  
  /**
   * @callback authSuccess
   * @param {CognitoUserSession} session The new session.
   * @param {bool=} userConfirmationNecessary User must be confirmed.
   */
  var isBrowser = typeof navigator !== 'undefined';
  var userAgent = isBrowser ? navigator.userAgent : 'nodejs';
  /** @class */
  
  var CognitoUser = /*#__PURE__*/function () {
    /**
     * Constructs a new CognitoUser object
     * @param {object} data Creation options
     * @param {string} data.Username The user's username.
     * @param {CognitoUserPool} data.Pool Pool containing the user.
     * @param {object} data.Storage Optional storage object.
     */
    function CognitoUser(data) {
      if (data == null || data.Username == null || data.Pool == null) {
        throw new Error('Username and pool information are required.');
      }
  
      this.username = data.Username || '';
      this.pool = data.Pool;
      this.Session = null;
      this.client = data.Pool.client;
      this.signInUserSession = null;
      this.authenticationFlowType = 'USER_SRP_AUTH';
      this.storage = data.Storage || new _StorageHelper["default"]().getStorage();
      this.keyPrefix = "CognitoIdentityServiceProvider." + this.pool.getClientId();
      this.userDataKey = this.keyPrefix + "." + this.username + ".userData";
    }
    /**
     * Sets the session for this user
     * @param {CognitoUserSession} signInUserSession the session
     * @returns {void}
     */
  
  
    var _proto = CognitoUser.prototype;
  
    _proto.setSignInUserSession = function setSignInUserSession(signInUserSession) {
      this.clearCachedUserData();
      this.signInUserSession = signInUserSession;
      this.cacheTokens();
    }
    /**
     * @returns {CognitoUserSession} the current session for this user
     */
    ;
  
    _proto.getSignInUserSession = function getSignInUserSession() {
      return this.signInUserSession;
    }
    /**
     * @returns {string} the user's username
     */
    ;
  
    _proto.getUsername = function getUsername() {
      return this.username;
    }
    /**
     * @returns {String} the authentication flow type
     */
    ;
  
    _proto.getAuthenticationFlowType = function getAuthenticationFlowType() {
      return this.authenticationFlowType;
    }
    /**
     * sets authentication flow type
     * @param {string} authenticationFlowType New value.
     * @returns {void}
     */
    ;
  
    _proto.setAuthenticationFlowType = function setAuthenticationFlowType(authenticationFlowType) {
      this.authenticationFlowType = authenticationFlowType;
    }
    /**
     * This is used for authenticating the user through the custom authentication flow.
     * @param {AuthenticationDetails} authDetails Contains the authentication data
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {customChallenge} callback.customChallenge Custom challenge
     *        response required to continue.
     * @param {authSuccess} callback.onSuccess Called on success with the new session.
     * @returns {void}
     */
    ;
  
    _proto.initiateAuth = function initiateAuth(authDetails, callback) {
      var _this = this;
  
      var authParameters = authDetails.getAuthParameters();
      authParameters.USERNAME = this.username;
      var clientMetaData = Object.keys(authDetails.getValidationData()).length !== 0 ? authDetails.getValidationData() : authDetails.getClientMetadata();
      var jsonReq = {
        AuthFlow: 'CUSTOM_AUTH',
        ClientId: this.pool.getClientId(),
        AuthParameters: authParameters,
        ClientMetadata: clientMetaData
      };
  
      if (this.getUserContextData()) {
        jsonReq.UserContextData = this.getUserContextData();
      }
  
      this.client.request('InitiateAuth', jsonReq, function (err, data) {
        if (err) {
          return callback.onFailure(err);
        }
  
        var challengeName = data.ChallengeName;
        var challengeParameters = data.ChallengeParameters;
  
        if (challengeName === 'CUSTOM_CHALLENGE') {
          _this.Session = data.Session;
          return callback.customChallenge(challengeParameters);
        }
  
        _this.signInUserSession = _this.getCognitoUserSession(data.AuthenticationResult);
  
        _this.cacheTokens();
  
        return callback.onSuccess(_this.signInUserSession);
      });
    }
    /**
     * This is used for authenticating the user.
     * stuff
     * @param {AuthenticationDetails} authDetails Contains the authentication data
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {newPasswordRequired} callback.newPasswordRequired new
     *        password and any required attributes are required to continue
     * @param {mfaRequired} callback.mfaRequired MFA code
     *        required to continue.
     * @param {customChallenge} callback.customChallenge Custom challenge
     *        response required to continue.
     * @param {authSuccess} callback.onSuccess Called on success with the new session.
     * @returns {void}
     */
    ;
  
    _proto.authenticateUser = function authenticateUser(authDetails, callback) {
      if (this.authenticationFlowType === 'USER_PASSWORD_AUTH') {
        return this.authenticateUserPlainUsernamePassword(authDetails, callback);
      } else if (this.authenticationFlowType === 'USER_SRP_AUTH' || this.authenticationFlowType === 'CUSTOM_AUTH') {
        return this.authenticateUserDefaultAuth(authDetails, callback);
      }
  
      return callback.onFailure(new Error('Authentication flow type is invalid.'));
    }
    /**
     * PRIVATE ONLY: This is an internal only method and should not
     * be directly called by the consumers.
     * It calls the AuthenticationHelper for SRP related
     * stuff
     * @param {AuthenticationDetails} authDetails Contains the authentication data
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {newPasswordRequired} callback.newPasswordRequired new
     *        password and any required attributes are required to continue
     * @param {mfaRequired} callback.mfaRequired MFA code
     *        required to continue.
     * @param {customChallenge} callback.customChallenge Custom challenge
     *        response required to continue.
     * @param {authSuccess} callback.onSuccess Called on success with the new session.
     * @returns {void}
     */
    ;
  
    _proto.authenticateUserDefaultAuth = function authenticateUserDefaultAuth(authDetails, callback) {
      var _this2 = this;
  
      var authenticationHelper = new _AuthenticationHelper["default"](this.pool.getUserPoolId().split('_')[1]);
      var dateHelper = new _DateHelper["default"]();
      var serverBValue;
      var salt;
      var authParameters = {};
  
      if (this.deviceKey != null) {
        authParameters.DEVICE_KEY = this.deviceKey;
      }
  
      authParameters.USERNAME = this.username;
      authenticationHelper.getLargeAValue(function (errOnAValue, aValue) {
        // getLargeAValue callback start
        if (errOnAValue) {
          callback.onFailure(errOnAValue);
        }
  
        authParameters.SRP_A = aValue.toString(16);
  
        if (_this2.authenticationFlowType === 'CUSTOM_AUTH') {
          authParameters.CHALLENGE_NAME = 'SRP_A';
        }
  
        var clientMetaData = Object.keys(authDetails.getValidationData()).length !== 0 ? authDetails.getValidationData() : authDetails.getClientMetadata();
        var jsonReq = {
          AuthFlow: _this2.authenticationFlowType,
          ClientId: _this2.pool.getClientId(),
          AuthParameters: authParameters,
          ClientMetadata: clientMetaData
        };
  
        if (_this2.getUserContextData(_this2.username)) {
          jsonReq.UserContextData = _this2.getUserContextData(_this2.username);
        }
  
        _this2.client.request('InitiateAuth', jsonReq, function (err, data) {
          if (err) {
            return callback.onFailure(err);
          }
  
          var challengeParameters = data.ChallengeParameters;
          _this2.username = challengeParameters.USER_ID_FOR_SRP;
          serverBValue = new _BigInteger["default"](challengeParameters.SRP_B, 16);
          salt = new _BigInteger["default"](challengeParameters.SALT, 16);
  
          _this2.getCachedDeviceKeyAndPassword();
  
          authenticationHelper.getPasswordAuthenticationKey(_this2.username, authDetails.getPassword(), serverBValue, salt, function (errOnHkdf, hkdf) {
            // getPasswordAuthenticationKey callback start
            if (errOnHkdf) {
              callback.onFailure(errOnHkdf);
            }
  
            var dateNow = dateHelper.getNowString();
  
            var message = _core["default"].lib.WordArray.create(_buffer.Buffer.concat([_buffer.Buffer.from(_this2.pool.getUserPoolId().split('_')[1], 'utf8'), _buffer.Buffer.from(_this2.username, 'utf8'), _buffer.Buffer.from(challengeParameters.SECRET_BLOCK, 'base64'), _buffer.Buffer.from(dateNow, 'utf8')]));
  
            var key = _core["default"].lib.WordArray.create(hkdf);
  
            var signatureString = _encBase["default"].stringify((0, _hmacSha["default"])(message, key));
  
            var challengeResponses = {};
            challengeResponses.USERNAME = _this2.username;
            challengeResponses.PASSWORD_CLAIM_SECRET_BLOCK = challengeParameters.SECRET_BLOCK;
            challengeResponses.TIMESTAMP = dateNow;
            challengeResponses.PASSWORD_CLAIM_SIGNATURE = signatureString;
  
            if (_this2.deviceKey != null) {
              challengeResponses.DEVICE_KEY = _this2.deviceKey;
            }
  
            var respondToAuthChallenge = function respondToAuthChallenge(challenge, challengeCallback) {
              return _this2.client.request('RespondToAuthChallenge', challenge, function (errChallenge, dataChallenge) {
                if (errChallenge && errChallenge.code === 'ResourceNotFoundException' && errChallenge.message.toLowerCase().indexOf('device') !== -1) {
                  challengeResponses.DEVICE_KEY = null;
                  _this2.deviceKey = null;
                  _this2.randomPassword = null;
                  _this2.deviceGroupKey = null;
  
                  _this2.clearCachedDeviceKeyAndPassword();
  
                  return respondToAuthChallenge(challenge, challengeCallback);
                }
  
                return challengeCallback(errChallenge, dataChallenge);
              });
            };
  
            var jsonReqResp = {
              ChallengeName: 'PASSWORD_VERIFIER',
              ClientId: _this2.pool.getClientId(),
              ChallengeResponses: challengeResponses,
              Session: data.Session,
              ClientMetadata: clientMetaData
            };
  
            if (_this2.getUserContextData()) {
              jsonReqResp.UserContextData = _this2.getUserContextData();
            }
  
            respondToAuthChallenge(jsonReqResp, function (errAuthenticate, dataAuthenticate) {
              if (errAuthenticate) {
                return callback.onFailure(errAuthenticate);
              }
  
              return _this2.authenticateUserInternal(dataAuthenticate, authenticationHelper, callback);
            });
            return undefined; // getPasswordAuthenticationKey callback end
          });
          return undefined;
        }); // getLargeAValue callback end
  
      });
    }
    /**
     * PRIVATE ONLY: This is an internal only method and should not
     * be directly called by the consumers.
     * @param {AuthenticationDetails} authDetails Contains the authentication data.
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {mfaRequired} callback.mfaRequired MFA code
     *        required to continue.
     * @param {authSuccess} callback.onSuccess Called on success with the new session.
     * @returns {void}
     */
    ;
  
    _proto.authenticateUserPlainUsernamePassword = function authenticateUserPlainUsernamePassword(authDetails, callback) {
      var _this3 = this;
  
      var authParameters = {};
      authParameters.USERNAME = this.username;
      authParameters.PASSWORD = authDetails.getPassword();
  
      if (!authParameters.PASSWORD) {
        callback.onFailure(new Error('PASSWORD parameter is required'));
        return;
      }
  
      var authenticationHelper = new _AuthenticationHelper["default"](this.pool.getUserPoolId().split('_')[1]);
      this.getCachedDeviceKeyAndPassword();
  
      if (this.deviceKey != null) {
        authParameters.DEVICE_KEY = this.deviceKey;
      }
  
      var clientMetaData = Object.keys(authDetails.getValidationData()).length !== 0 ? authDetails.getValidationData() : authDetails.getClientMetadata();
      var jsonReq = {
        AuthFlow: 'USER_PASSWORD_AUTH',
        ClientId: this.pool.getClientId(),
        AuthParameters: authParameters,
        ClientMetadata: clientMetaData
      };
  
      if (this.getUserContextData(this.username)) {
        jsonReq.UserContextData = this.getUserContextData(this.username);
      } // USER_PASSWORD_AUTH happens in a single round-trip: client sends userName and password,
      // Cognito UserPools verifies password and returns tokens.
  
  
      this.client.request('InitiateAuth', jsonReq, function (err, authResult) {
        if (err) {
          return callback.onFailure(err);
        }
  
        return _this3.authenticateUserInternal(authResult, authenticationHelper, callback);
      });
    }
    /**
     * PRIVATE ONLY: This is an internal only method and should not
     * be directly called by the consumers.
     * @param {object} dataAuthenticate authentication data
     * @param {object} authenticationHelper helper created
     * @param {callback} callback passed on from caller
     * @returns {void}
     */
    ;
  
    _proto.authenticateUserInternal = function authenticateUserInternal(dataAuthenticate, authenticationHelper, callback) {
      var _this4 = this;
  
      var challengeName = dataAuthenticate.ChallengeName;
      var challengeParameters = dataAuthenticate.ChallengeParameters;
  
      if (challengeName === 'SMS_MFA') {
        this.Session = dataAuthenticate.Session;
        return callback.mfaRequired(challengeName, challengeParameters);
      }
  
      if (challengeName === 'SELECT_MFA_TYPE') {
        this.Session = dataAuthenticate.Session;
        return callback.selectMFAType(challengeName, challengeParameters);
      }
  
      if (challengeName === 'MFA_SETUP') {
        this.Session = dataAuthenticate.Session;
        return callback.mfaSetup(challengeName, challengeParameters);
      }
  
      if (challengeName === 'SOFTWARE_TOKEN_MFA') {
        this.Session = dataAuthenticate.Session;
        return callback.totpRequired(challengeName, challengeParameters);
      }
  
      if (challengeName === 'CUSTOM_CHALLENGE') {
        this.Session = dataAuthenticate.Session;
        return callback.customChallenge(challengeParameters);
      }
  
      if (challengeName === 'NEW_PASSWORD_REQUIRED') {
        this.Session = dataAuthenticate.Session;
        var userAttributes = null;
        var rawRequiredAttributes = null;
        var requiredAttributes = [];
        var userAttributesPrefix = authenticationHelper.getNewPasswordRequiredChallengeUserAttributePrefix();
  
        if (challengeParameters) {
          userAttributes = JSON.parse(dataAuthenticate.ChallengeParameters.userAttributes);
          rawRequiredAttributes = JSON.parse(dataAuthenticate.ChallengeParameters.requiredAttributes);
        }
  
        if (rawRequiredAttributes) {
          for (var i = 0; i < rawRequiredAttributes.length; i++) {
            requiredAttributes[i] = rawRequiredAttributes[i].substr(userAttributesPrefix.length);
          }
        }
  
        return callback.newPasswordRequired(userAttributes, requiredAttributes);
      }
  
      if (challengeName === 'DEVICE_SRP_AUTH') {
        this.getDeviceResponse(callback);
        return undefined;
      }
  
      this.signInUserSession = this.getCognitoUserSession(dataAuthenticate.AuthenticationResult);
      this.challengeName = challengeName;
      this.cacheTokens();
      var newDeviceMetadata = dataAuthenticate.AuthenticationResult.NewDeviceMetadata;
  
      if (newDeviceMetadata == null) {
        return callback.onSuccess(this.signInUserSession);
      }
  
      authenticationHelper.generateHashDevice(dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceGroupKey, dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey, function (errGenHash) {
        if (errGenHash) {
          return callback.onFailure(errGenHash);
        }
  
        var deviceSecretVerifierConfig = {
          Salt: _buffer.Buffer.from(authenticationHelper.getSaltDevices(), 'hex').toString('base64'),
          PasswordVerifier: _buffer.Buffer.from(authenticationHelper.getVerifierDevices(), 'hex').toString('base64')
        };
        _this4.verifierDevices = deviceSecretVerifierConfig.PasswordVerifier;
        _this4.deviceGroupKey = newDeviceMetadata.DeviceGroupKey;
        _this4.randomPassword = authenticationHelper.getRandomPassword();
  
        _this4.client.request('ConfirmDevice', {
          DeviceKey: newDeviceMetadata.DeviceKey,
          AccessToken: _this4.signInUserSession.getAccessToken().getJwtToken(),
          DeviceSecretVerifierConfig: deviceSecretVerifierConfig,
          DeviceName: userAgent
        }, function (errConfirm, dataConfirm) {
          if (errConfirm) {
            return callback.onFailure(errConfirm);
          }
  
          _this4.deviceKey = dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey;
  
          _this4.cacheDeviceKeyAndPassword();
  
          if (dataConfirm.UserConfirmationNecessary === true) {
            return callback.onSuccess(_this4.signInUserSession, dataConfirm.UserConfirmationNecessary);
          }
  
          return callback.onSuccess(_this4.signInUserSession);
        });
  
        return undefined;
      });
      return undefined;
    }
    /**
     * This method is user to complete the NEW_PASSWORD_REQUIRED challenge.
     * Pass the new password with any new user attributes to be updated.
     * User attribute keys must be of format userAttributes.<attribute_name>.
     * @param {string} newPassword new password for this user
     * @param {object} requiredAttributeData map with values for all required attributes
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {mfaRequired} callback.mfaRequired MFA code required to continue.
     * @param {customChallenge} callback.customChallenge Custom challenge
     *         response required to continue.
     * @param {authSuccess} callback.onSuccess Called on success with the new session.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     */
    ;
  
    _proto.completeNewPasswordChallenge = function completeNewPasswordChallenge(newPassword, requiredAttributeData, callback, clientMetadata) {
      var _this5 = this;
  
      if (!newPassword) {
        return callback.onFailure(new Error('New password is required.'));
      }
  
      var authenticationHelper = new _AuthenticationHelper["default"](this.pool.getUserPoolId().split('_')[1]);
      var userAttributesPrefix = authenticationHelper.getNewPasswordRequiredChallengeUserAttributePrefix();
      var finalUserAttributes = {};
  
      if (requiredAttributeData) {
        Object.keys(requiredAttributeData).forEach(function (key) {
          finalUserAttributes[userAttributesPrefix + key] = requiredAttributeData[key];
        });
      }
  
      finalUserAttributes.NEW_PASSWORD = newPassword;
      finalUserAttributes.USERNAME = this.username;
      var jsonReq = {
        ChallengeName: 'NEW_PASSWORD_REQUIRED',
        ClientId: this.pool.getClientId(),
        ChallengeResponses: finalUserAttributes,
        Session: this.Session,
        ClientMetadata: clientMetadata
      };
  
      if (this.getUserContextData()) {
        jsonReq.UserContextData = this.getUserContextData();
      }
  
      this.client.request('RespondToAuthChallenge', jsonReq, function (errAuthenticate, dataAuthenticate) {
        if (errAuthenticate) {
          return callback.onFailure(errAuthenticate);
        }
  
        return _this5.authenticateUserInternal(dataAuthenticate, authenticationHelper, callback);
      });
      return undefined;
    }
    /**
     * This is used to get a session using device authentication. It is called at the end of user
     * authentication
     *
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {authSuccess} callback.onSuccess Called on success with the new session.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     * @private
     */
    ;
  
    _proto.getDeviceResponse = function getDeviceResponse(callback, clientMetadata) {
      var _this6 = this;
  
      var authenticationHelper = new _AuthenticationHelper["default"](this.deviceGroupKey);
      var dateHelper = new _DateHelper["default"]();
      var authParameters = {};
      authParameters.USERNAME = this.username;
      authParameters.DEVICE_KEY = this.deviceKey;
      authenticationHelper.getLargeAValue(function (errAValue, aValue) {
        // getLargeAValue callback start
        if (errAValue) {
          callback.onFailure(errAValue);
        }
  
        authParameters.SRP_A = aValue.toString(16);
        var jsonReq = {
          ChallengeName: 'DEVICE_SRP_AUTH',
          ClientId: _this6.pool.getClientId(),
          ChallengeResponses: authParameters,
          ClientMetadata: clientMetadata
        };
  
        if (_this6.getUserContextData()) {
          jsonReq.UserContextData = _this6.getUserContextData();
        }
  
        _this6.client.request('RespondToAuthChallenge', jsonReq, function (err, data) {
          if (err) {
            return callback.onFailure(err);
          }
  
          var challengeParameters = data.ChallengeParameters;
          var serverBValue = new _BigInteger["default"](challengeParameters.SRP_B, 16);
          var salt = new _BigInteger["default"](challengeParameters.SALT, 16);
          authenticationHelper.getPasswordAuthenticationKey(_this6.deviceKey, _this6.randomPassword, serverBValue, salt, function (errHkdf, hkdf) {
            // getPasswordAuthenticationKey callback start
            if (errHkdf) {
              return callback.onFailure(errHkdf);
            }
  
            var dateNow = dateHelper.getNowString();
  
            var message = _core["default"].lib.WordArray.create(_buffer.Buffer.concat([_buffer.Buffer.from(_this6.deviceGroupKey, 'utf8'), _buffer.Buffer.from(_this6.deviceKey, 'utf8'), _buffer.Buffer.from(challengeParameters.SECRET_BLOCK, 'base64'), _buffer.Buffer.from(dateNow, 'utf8')]));
  
            var key = _core["default"].lib.WordArray.create(hkdf);
  
            var signatureString = _encBase["default"].stringify((0, _hmacSha["default"])(message, key));
  
            var challengeResponses = {};
            challengeResponses.USERNAME = _this6.username;
            challengeResponses.PASSWORD_CLAIM_SECRET_BLOCK = challengeParameters.SECRET_BLOCK;
            challengeResponses.TIMESTAMP = dateNow;
            challengeResponses.PASSWORD_CLAIM_SIGNATURE = signatureString;
            challengeResponses.DEVICE_KEY = _this6.deviceKey;
            var jsonReqResp = {
              ChallengeName: 'DEVICE_PASSWORD_VERIFIER',
              ClientId: _this6.pool.getClientId(),
              ChallengeResponses: challengeResponses,
              Session: data.Session
            };
  
            if (_this6.getUserContextData()) {
              jsonReqResp.UserContextData = _this6.getUserContextData();
            }
  
            _this6.client.request('RespondToAuthChallenge', jsonReqResp, function (errAuthenticate, dataAuthenticate) {
              if (errAuthenticate) {
                return callback.onFailure(errAuthenticate);
              }
  
              _this6.signInUserSession = _this6.getCognitoUserSession(dataAuthenticate.AuthenticationResult);
  
              _this6.cacheTokens();
  
              return callback.onSuccess(_this6.signInUserSession);
            });
  
            return undefined; // getPasswordAuthenticationKey callback end
          });
          return undefined;
        }); // getLargeAValue callback end
  
      });
    }
    /**
     * This is used for a certain user to confirm the registration by using a confirmation code
     * @param {string} confirmationCode Code entered by user.
     * @param {bool} forceAliasCreation Allow migrating from an existing email / phone number.
     * @param {nodeCallback<string>} callback Called on success or error.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     */
    ;
  
    _proto.confirmRegistration = function confirmRegistration(confirmationCode, forceAliasCreation, callback, clientMetadata) {
      var jsonReq = {
        ClientId: this.pool.getClientId(),
        ConfirmationCode: confirmationCode,
        Username: this.username,
        ForceAliasCreation: forceAliasCreation,
        ClientMetadata: clientMetadata
      };
  
      if (this.getUserContextData()) {
        jsonReq.UserContextData = this.getUserContextData();
      }
  
      this.client.request('ConfirmSignUp', jsonReq, function (err) {
        if (err) {
          return callback(err, null);
        }
  
        return callback(null, 'SUCCESS');
      });
    }
    /**
     * This is used by the user once he has the responses to a custom challenge
     * @param {string} answerChallenge The custom challenge answer.
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {customChallenge} callback.customChallenge
     *    Custom challenge response required to continue.
     * @param {authSuccess} callback.onSuccess Called on success with the new session.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     */
    ;
  
    _proto.sendCustomChallengeAnswer = function sendCustomChallengeAnswer(answerChallenge, callback, clientMetadata) {
      var _this7 = this;
  
      var challengeResponses = {};
      challengeResponses.USERNAME = this.username;
      challengeResponses.ANSWER = answerChallenge;
      var authenticationHelper = new _AuthenticationHelper["default"](this.pool.getUserPoolId().split('_')[1]);
      this.getCachedDeviceKeyAndPassword();
  
      if (this.deviceKey != null) {
        challengeResponses.DEVICE_KEY = this.deviceKey;
      }
  
      var jsonReq = {
        ChallengeName: 'CUSTOM_CHALLENGE',
        ChallengeResponses: challengeResponses,
        ClientId: this.pool.getClientId(),
        Session: this.Session,
        ClientMetadata: clientMetadata
      };
  
      if (this.getUserContextData()) {
        jsonReq.UserContextData = this.getUserContextData();
      }
  
      this.client.request('RespondToAuthChallenge', jsonReq, function (err, data) {
        if (err) {
          return callback.onFailure(err);
        }
  
        return _this7.authenticateUserInternal(data, authenticationHelper, callback);
      });
    }
    /**
     * This is used by the user once he has an MFA code
     * @param {string} confirmationCode The MFA code entered by the user.
     * @param {object} callback Result callback map.
     * @param {string} mfaType The mfa we are replying to.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {authSuccess} callback.onSuccess Called on success with the new session.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     */
    ;
  
    _proto.sendMFACode = function sendMFACode(confirmationCode, callback, mfaType, clientMetadata) {
      var _this8 = this;
  
      var challengeResponses = {};
      challengeResponses.USERNAME = this.username;
      challengeResponses.SMS_MFA_CODE = confirmationCode;
      var mfaTypeSelection = mfaType || 'SMS_MFA';
  
      if (mfaTypeSelection === 'SOFTWARE_TOKEN_MFA') {
        challengeResponses.SOFTWARE_TOKEN_MFA_CODE = confirmationCode;
      }
  
      if (this.deviceKey != null) {
        challengeResponses.DEVICE_KEY = this.deviceKey;
      }
  
      var jsonReq = {
        ChallengeName: mfaTypeSelection,
        ChallengeResponses: challengeResponses,
        ClientId: this.pool.getClientId(),
        Session: this.Session,
        ClientMetadata: clientMetadata
      };
  
      if (this.getUserContextData()) {
        jsonReq.UserContextData = this.getUserContextData();
      }
  
      this.client.request('RespondToAuthChallenge', jsonReq, function (err, dataAuthenticate) {
        if (err) {
          return callback.onFailure(err);
        }
  
        var challengeName = dataAuthenticate.ChallengeName;
  
        if (challengeName === 'DEVICE_SRP_AUTH') {
          _this8.getDeviceResponse(callback);
  
          return undefined;
        }
  
        _this8.signInUserSession = _this8.getCognitoUserSession(dataAuthenticate.AuthenticationResult);
  
        _this8.cacheTokens();
  
        if (dataAuthenticate.AuthenticationResult.NewDeviceMetadata == null) {
          return callback.onSuccess(_this8.signInUserSession);
        }
  
        var authenticationHelper = new _AuthenticationHelper["default"](_this8.pool.getUserPoolId().split('_')[1]);
        authenticationHelper.generateHashDevice(dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceGroupKey, dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey, function (errGenHash) {
          if (errGenHash) {
            return callback.onFailure(errGenHash);
          }
  
          var deviceSecretVerifierConfig = {
            Salt: _buffer.Buffer.from(authenticationHelper.getSaltDevices(), 'hex').toString('base64'),
            PasswordVerifier: _buffer.Buffer.from(authenticationHelper.getVerifierDevices(), 'hex').toString('base64')
          };
          _this8.verifierDevices = deviceSecretVerifierConfig.PasswordVerifier;
          _this8.deviceGroupKey = dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceGroupKey;
          _this8.randomPassword = authenticationHelper.getRandomPassword();
  
          _this8.client.request('ConfirmDevice', {
            DeviceKey: dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey,
            AccessToken: _this8.signInUserSession.getAccessToken().getJwtToken(),
            DeviceSecretVerifierConfig: deviceSecretVerifierConfig,
            DeviceName: userAgent
          }, function (errConfirm, dataConfirm) {
            if (errConfirm) {
              return callback.onFailure(errConfirm);
            }
  
            _this8.deviceKey = dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey;
  
            _this8.cacheDeviceKeyAndPassword();
  
            if (dataConfirm.UserConfirmationNecessary === true) {
              return callback.onSuccess(_this8.signInUserSession, dataConfirm.UserConfirmationNecessary);
            }
  
            return callback.onSuccess(_this8.signInUserSession);
          });
  
          return undefined;
        });
        return undefined;
      });
    }
    /**
     * This is used by an authenticated user to change the current password
     * @param {string} oldUserPassword The current password.
     * @param {string} newUserPassword The requested new password.
     * @param {nodeCallback<string>} callback Called on success or error.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     */
    ;
  
    _proto.changePassword = function changePassword(oldUserPassword, newUserPassword, callback, clientMetadata) {
      if (!(this.signInUserSession != null && this.signInUserSession.isValid())) {
        return callback(new Error('User is not authenticated'), null);
      }
  
      this.client.request('ChangePassword', {
        PreviousPassword: oldUserPassword,
        ProposedPassword: newUserPassword,
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken(),
        ClientMetadata: clientMetadata
      }, function (err) {
        if (err) {
          return callback(err, null);
        }
  
        return callback(null, 'SUCCESS');
      });
      return undefined;
    }
    /**
     * This is used by an authenticated user to enable MFA for itself
     * @deprecated
     * @param {nodeCallback<string>} callback Called on success or error.
     * @returns {void}
     */
    ;
  
    _proto.enableMFA = function enableMFA(callback) {
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback(new Error('User is not authenticated'), null);
      }
  
      var mfaOptions = [];
      var mfaEnabled = {
        DeliveryMedium: 'SMS',
        AttributeName: 'phone_number'
      };
      mfaOptions.push(mfaEnabled);
      this.client.request('SetUserSettings', {
        MFAOptions: mfaOptions,
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken()
      }, function (err) {
        if (err) {
          return callback(err, null);
        }
  
        return callback(null, 'SUCCESS');
      });
      return undefined;
    }
    /**
     * This is used by an authenticated user to enable MFA for itself
     * @param {IMfaSettings} smsMfaSettings the sms mfa settings
     * @param {IMFASettings} softwareTokenMfaSettings the software token mfa settings
     * @param {nodeCallback<string>} callback Called on success or error.
     * @returns {void}
     */
    ;
  
    _proto.setUserMfaPreference = function setUserMfaPreference(smsMfaSettings, softwareTokenMfaSettings, callback) {
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback(new Error('User is not authenticated'), null);
      }
  
      this.client.request('SetUserMFAPreference', {
        SMSMfaSettings: smsMfaSettings,
        SoftwareTokenMfaSettings: softwareTokenMfaSettings,
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken()
      }, function (err) {
        if (err) {
          return callback(err, null);
        }
  
        return callback(null, 'SUCCESS');
      });
      return undefined;
    }
    /**
     * This is used by an authenticated user to disable MFA for itself
     * @deprecated
     * @param {nodeCallback<string>} callback Called on success or error.
     * @returns {void}
     */
    ;
  
    _proto.disableMFA = function disableMFA(callback) {
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback(new Error('User is not authenticated'), null);
      }
  
      var mfaOptions = [];
      this.client.request('SetUserSettings', {
        MFAOptions: mfaOptions,
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken()
      }, function (err) {
        if (err) {
          return callback(err, null);
        }
  
        return callback(null, 'SUCCESS');
      });
      return undefined;
    }
    /**
     * This is used by an authenticated user to delete itself
     * @param {nodeCallback<string>} callback Called on success or error.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     */
    ;
  
    _proto.deleteUser = function deleteUser(callback, clientMetadata) {
      var _this9 = this;
  
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback(new Error('User is not authenticated'), null);
      }
  
      this.client.request('DeleteUser', {
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken(),
        ClientMetadata: clientMetadata
      }, function (err) {
        if (err) {
          return callback(err, null);
        }
  
        _this9.clearCachedUser();
  
        return callback(null, 'SUCCESS');
      });
      return undefined;
    }
    /**
     * @typedef {CognitoUserAttribute | { Name:string, Value:string }} AttributeArg
     */
  
    /**
     * This is used by an authenticated user to change a list of attributes
     * @param {AttributeArg[]} attributes A list of the new user attributes.
     * @param {nodeCallback<string>} callback Called on success or error.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     */
    ;
  
    _proto.updateAttributes = function updateAttributes(attributes, callback, clientMetadata) {
      var _this10 = this;
  
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback(new Error('User is not authenticated'), null);
      }
  
      this.client.request('UpdateUserAttributes', {
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken(),
        UserAttributes: attributes,
        ClientMetadata: clientMetadata
      }, function (err) {
        if (err) {
          return callback(err, null);
        } // update cached user
  
  
        return _this10.getUserData(function () {
          return callback(null, 'SUCCESS');
        }, {
          bypassCache: true
        });
      });
      return undefined;
    }
    /**
     * This is used by an authenticated user to get a list of attributes
     * @param {nodeCallback<CognitoUserAttribute[]>} callback Called on success or error.
     * @returns {void}
     */
    ;
  
    _proto.getUserAttributes = function getUserAttributes(callback) {
      if (!(this.signInUserSession != null && this.signInUserSession.isValid())) {
        return callback(new Error('User is not authenticated'), null);
      }
  
      this.client.request('GetUser', {
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken()
      }, function (err, userData) {
        if (err) {
          return callback(err, null);
        }
  
        var attributeList = [];
  
        for (var i = 0; i < userData.UserAttributes.length; i++) {
          var attribute = {
            Name: userData.UserAttributes[i].Name,
            Value: userData.UserAttributes[i].Value
          };
          var userAttribute = new _CognitoUserAttribute["default"](attribute);
          attributeList.push(userAttribute);
        }
  
        return callback(null, attributeList);
      });
      return undefined;
    }
    /**
     * This is used by an authenticated user to get the MFAOptions
     * @param {nodeCallback<MFAOptions>} callback Called on success or error.
     * @returns {void}
     */
    ;
  
    _proto.getMFAOptions = function getMFAOptions(callback) {
      if (!(this.signInUserSession != null && this.signInUserSession.isValid())) {
        return callback(new Error('User is not authenticated'), null);
      }
  
      this.client.request('GetUser', {
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken()
      }, function (err, userData) {
        if (err) {
          return callback(err, null);
        }
  
        return callback(null, userData.MFAOptions);
      });
      return undefined;
    }
    /**
     * PRIVATE ONLY: This is an internal only method and should not
     * be directly called by the consumers.
     */
    ;
  
    _proto.createGetUserRequest = function createGetUserRequest() {
      return this.client.promisifyRequest('GetUser', {
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken()
      });
    }
    /**
     * PRIVATE ONLY: This is an internal only method and should not
     * be directly called by the consumers.
     */
    ;
  
    _proto.refreshSessionIfPossible = function refreshSessionIfPossible() {
      var _this11 = this;
  
      // best effort, if not possible
      return new Promise(function (resolve) {
        var refresh = _this11.signInUserSession.getRefreshToken();
  
        if (refresh && refresh.getToken()) {
          _this11.refreshSession(refresh, resolve);
        } else {
          resolve();
        }
      });
    }
    /**
     * This is used by an authenticated users to get the userData
     * @param {nodeCallback<UserData>} callback Called on success or error.
     * @param {GetUserDataOptions} params
     * @returns {void}
     */
    ;
  
    _proto.getUserData = function getUserData(callback, params) {
      var _this12 = this;
  
      if (!(this.signInUserSession != null && this.signInUserSession.isValid())) {
        this.clearCachedUserData();
        return callback(new Error('User is not authenticated'), null);
      }
  
      var userData = this.getUserDataFromCache();
  
      if (!userData) {
        this.fetchUserData().then(function (data) {
          callback(null, data);
        })["catch"](callback);
        return;
      }
  
      if (this.isFetchUserDataAndTokenRequired(params)) {
        this.fetchUserData().then(function (data) {
          return _this12.refreshSessionIfPossible().then(function () {
            return data;
          });
        }).then(function (data) {
          return callback(null, data);
        })["catch"](callback);
        return;
      }
  
      try {
        callback(null, JSON.parse(userData));
        return;
      } catch (err) {
        this.clearCachedUserData();
        callback(err, null);
        return;
      }
    }
    /**
     *
     * PRIVATE ONLY: This is an internal only method and should not
     * be directly called by the consumers.
     */
    ;
  
    _proto.getUserDataFromCache = function getUserDataFromCache() {
      var userData = this.storage.getItem(this.userDataKey);
      return userData;
    }
    /**
     *
     * PRIVATE ONLY: This is an internal only method and should not
     * be directly called by the consumers.
     */
    ;
  
    _proto.isFetchUserDataAndTokenRequired = function isFetchUserDataAndTokenRequired(params) {
      var _ref = params || {},
          _ref$bypassCache = _ref.bypassCache,
          bypassCache = _ref$bypassCache === void 0 ? false : _ref$bypassCache;
  
      return bypassCache;
    }
    /**
     *
     * PRIVATE ONLY: This is an internal only method and should not
     * be directly called by the consumers.
     */
    ;
  
    _proto.fetchUserData = function fetchUserData() {
      var _this13 = this;
  
      return this.createGetUserRequest().then(function (data) {
        _this13.cacheUserData(data);
  
        return data;
      });
    }
    /**
     * This is used by an authenticated user to delete a list of attributes
     * @param {string[]} attributeList Names of the attributes to delete.
     * @param {nodeCallback<string>} callback Called on success or error.
     * @returns {void}
     */
    ;
  
    _proto.deleteAttributes = function deleteAttributes(attributeList, callback) {
      if (!(this.signInUserSession != null && this.signInUserSession.isValid())) {
        return callback(new Error('User is not authenticated'), null);
      }
  
      this.client.request('DeleteUserAttributes', {
        UserAttributeNames: attributeList,
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken()
      }, function (err) {
        if (err) {
          return callback(err, null);
        }
  
        return callback(null, 'SUCCESS');
      });
      return undefined;
    }
    /**
     * This is used by a user to resend a confirmation code
     * @param {nodeCallback<string>} callback Called on success or error.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     */
    ;
  
    _proto.resendConfirmationCode = function resendConfirmationCode(callback, clientMetadata) {
      var jsonReq = {
        ClientId: this.pool.getClientId(),
        Username: this.username,
        ClientMetadata: clientMetadata
      };
      this.client.request('ResendConfirmationCode', jsonReq, function (err, result) {
        if (err) {
          return callback(err, null);
        }
  
        return callback(null, result);
      });
    }
    /**
     * This is used to get a session, either from the session object
     * or from  the local storage, or by using a refresh token
     *
     * @param {nodeCallback<CognitoUserSession>} callback Called on success or error.
     * @returns {void}
     */
    ;
  
    _proto.getSession = function getSession(callback) {
      if (this.username == null) {
        return callback(new Error('Username is null. Cannot retrieve a new session'), null);
      }
  
      if (this.signInUserSession != null && this.signInUserSession.isValid()) {
        return callback(null, this.signInUserSession);
      }
  
      var keyPrefix = "CognitoIdentityServiceProvider." + this.pool.getClientId() + "." + this.username;
      var idTokenKey = keyPrefix + ".idToken";
      var accessTokenKey = keyPrefix + ".accessToken";
      var refreshTokenKey = keyPrefix + ".refreshToken";
      var clockDriftKey = keyPrefix + ".clockDrift";
  
      if (this.storage.getItem(idTokenKey)) {
        var idToken = new _CognitoIdToken["default"]({
          IdToken: this.storage.getItem(idTokenKey)
        });
        var accessToken = new _CognitoAccessToken["default"]({
          AccessToken: this.storage.getItem(accessTokenKey)
        });
        var refreshToken = new _CognitoRefreshToken["default"]({
          RefreshToken: this.storage.getItem(refreshTokenKey)
        });
        var clockDrift = parseInt(this.storage.getItem(clockDriftKey), 0) || 0;
        var sessionData = {
          IdToken: idToken,
          AccessToken: accessToken,
          RefreshToken: refreshToken,
          ClockDrift: clockDrift
        };
        var cachedSession = new _CognitoUserSession["default"](sessionData);
  
        if (cachedSession.isValid()) {
          this.signInUserSession = cachedSession;
          return callback(null, this.signInUserSession);
        }
  
        if (!refreshToken.getToken()) {
          return callback(new Error('Cannot retrieve a new session. Please authenticate.'), null);
        }
  
        this.refreshSession(refreshToken, callback);
      } else {
        callback(new Error('Local storage is missing an ID Token, Please authenticate'), null);
      }
  
      return undefined;
    }
    /**
     * This uses the refreshToken to retrieve a new session
     * @param {CognitoRefreshToken} refreshToken A previous session's refresh token.
     * @param {nodeCallback<CognitoUserSession>} callback Called on success or error.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     */
    ;
  
    _proto.refreshSession = function refreshSession(refreshToken, callback, clientMetadata) {
      var _this14 = this;
  
      var authParameters = {};
      authParameters.REFRESH_TOKEN = refreshToken.getToken();
      var keyPrefix = "CognitoIdentityServiceProvider." + this.pool.getClientId();
      var lastUserKey = keyPrefix + ".LastAuthUser";
  
      if (this.storage.getItem(lastUserKey)) {
        this.username = this.storage.getItem(lastUserKey);
        var deviceKeyKey = keyPrefix + "." + this.username + ".deviceKey";
        this.deviceKey = this.storage.getItem(deviceKeyKey);
        authParameters.DEVICE_KEY = this.deviceKey;
      }
  
      var jsonReq = {
        ClientId: this.pool.getClientId(),
        AuthFlow: 'REFRESH_TOKEN_AUTH',
        AuthParameters: authParameters,
        ClientMetadata: clientMetadata
      };
  
      if (this.getUserContextData()) {
        jsonReq.UserContextData = this.getUserContextData();
      }
  
      this.client.request('InitiateAuth', jsonReq, function (err, authResult) {
        if (err) {
          if (err.code === 'NotAuthorizedException') {
            _this14.clearCachedUser();
          }
  
          return callback(err, null);
        }
  
        if (authResult) {
          var authenticationResult = authResult.AuthenticationResult;
  
          if (!Object.prototype.hasOwnProperty.call(authenticationResult, 'RefreshToken')) {
            authenticationResult.RefreshToken = refreshToken.getToken();
          }
  
          _this14.signInUserSession = _this14.getCognitoUserSession(authenticationResult);
  
          _this14.cacheTokens();
  
          return callback(null, _this14.signInUserSession);
        }
  
        return undefined;
      });
    }
    /**
     * This is used to save the session tokens to local storage
     * @returns {void}
     */
    ;
  
    _proto.cacheTokens = function cacheTokens() {
      var keyPrefix = "CognitoIdentityServiceProvider." + this.pool.getClientId();
      var idTokenKey = keyPrefix + "." + this.username + ".idToken";
      var accessTokenKey = keyPrefix + "." + this.username + ".accessToken";
      var refreshTokenKey = keyPrefix + "." + this.username + ".refreshToken";
      var clockDriftKey = keyPrefix + "." + this.username + ".clockDrift";
      var lastUserKey = keyPrefix + ".LastAuthUser";
      this.storage.setItem(idTokenKey, this.signInUserSession.getIdToken().getJwtToken());
      this.storage.setItem(accessTokenKey, this.signInUserSession.getAccessToken().getJwtToken());
      this.storage.setItem(refreshTokenKey, this.signInUserSession.getRefreshToken().getToken());
      this.storage.setItem(clockDriftKey, "" + this.signInUserSession.getClockDrift());
      this.storage.setItem(lastUserKey, this.username);
    }
    /**
     * This is to cache user data
     */
    ;
  
    _proto.cacheUserData = function cacheUserData(userData) {
      this.storage.setItem(this.userDataKey, JSON.stringify(userData));
    }
    /**
     * This is to remove cached user data
     */
    ;
  
    _proto.clearCachedUserData = function clearCachedUserData() {
      this.storage.removeItem(this.userDataKey);
    };
  
    _proto.clearCachedUser = function clearCachedUser() {
      this.clearCachedTokens();
      this.clearCachedUserData();
    }
    /**
     * This is used to cache the device key and device group and device password
     * @returns {void}
     */
    ;
  
    _proto.cacheDeviceKeyAndPassword = function cacheDeviceKeyAndPassword() {
      var keyPrefix = "CognitoIdentityServiceProvider." + this.pool.getClientId() + "." + this.username;
      var deviceKeyKey = keyPrefix + ".deviceKey";
      var randomPasswordKey = keyPrefix + ".randomPasswordKey";
      var deviceGroupKeyKey = keyPrefix + ".deviceGroupKey";
      this.storage.setItem(deviceKeyKey, this.deviceKey);
      this.storage.setItem(randomPasswordKey, this.randomPassword);
      this.storage.setItem(deviceGroupKeyKey, this.deviceGroupKey);
    }
    /**
     * This is used to get current device key and device group and device password
     * @returns {void}
     */
    ;
  
    _proto.getCachedDeviceKeyAndPassword = function getCachedDeviceKeyAndPassword() {
      var keyPrefix = "CognitoIdentityServiceProvider." + this.pool.getClientId() + "." + this.username;
      var deviceKeyKey = keyPrefix + ".deviceKey";
      var randomPasswordKey = keyPrefix + ".randomPasswordKey";
      var deviceGroupKeyKey = keyPrefix + ".deviceGroupKey";
  
      if (this.storage.getItem(deviceKeyKey)) {
        this.deviceKey = this.storage.getItem(deviceKeyKey);
        this.randomPassword = this.storage.getItem(randomPasswordKey);
        this.deviceGroupKey = this.storage.getItem(deviceGroupKeyKey);
      }
    }
    /**
     * This is used to clear the device key info from local storage
     * @returns {void}
     */
    ;
  
    _proto.clearCachedDeviceKeyAndPassword = function clearCachedDeviceKeyAndPassword() {
      var keyPrefix = "CognitoIdentityServiceProvider." + this.pool.getClientId() + "." + this.username;
      var deviceKeyKey = keyPrefix + ".deviceKey";
      var randomPasswordKey = keyPrefix + ".randomPasswordKey";
      var deviceGroupKeyKey = keyPrefix + ".deviceGroupKey";
      this.storage.removeItem(deviceKeyKey);
      this.storage.removeItem(randomPasswordKey);
      this.storage.removeItem(deviceGroupKeyKey);
    }
    /**
     * This is used to clear the session tokens from local storage
     * @returns {void}
     */
    ;
  
    _proto.clearCachedTokens = function clearCachedTokens() {
      var keyPrefix = "CognitoIdentityServiceProvider." + this.pool.getClientId();
      var idTokenKey = keyPrefix + "." + this.username + ".idToken";
      var accessTokenKey = keyPrefix + "." + this.username + ".accessToken";
      var refreshTokenKey = keyPrefix + "." + this.username + ".refreshToken";
      var lastUserKey = keyPrefix + ".LastAuthUser";
      var clockDriftKey = keyPrefix + "." + this.username + ".clockDrift";
      this.storage.removeItem(idTokenKey);
      this.storage.removeItem(accessTokenKey);
      this.storage.removeItem(refreshTokenKey);
      this.storage.removeItem(lastUserKey);
      this.storage.removeItem(clockDriftKey);
    }
    /**
     * This is used to build a user session from tokens retrieved in the authentication result
     * @param {object} authResult Successful auth response from server.
     * @returns {CognitoUserSession} The new user session.
     * @private
     */
    ;
  
    _proto.getCognitoUserSession = function getCognitoUserSession(authResult) {
      var idToken = new _CognitoIdToken["default"](authResult);
      var accessToken = new _CognitoAccessToken["default"](authResult);
      var refreshToken = new _CognitoRefreshToken["default"](authResult);
      var sessionData = {
        IdToken: idToken,
        AccessToken: accessToken,
        RefreshToken: refreshToken
      };
      return new _CognitoUserSession["default"](sessionData);
    }
    /**
     * This is used to initiate a forgot password request
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {inputVerificationCode?} callback.inputVerificationCode
     *    Optional callback raised instead of onSuccess with response data.
     * @param {onSuccess} callback.onSuccess Called on success.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     */
    ;
  
    _proto.forgotPassword = function forgotPassword(callback, clientMetadata) {
      var jsonReq = {
        ClientId: this.pool.getClientId(),
        Username: this.username,
        ClientMetadata: clientMetadata
      };
  
      if (this.getUserContextData()) {
        jsonReq.UserContextData = this.getUserContextData();
      }
  
      this.client.request('ForgotPassword', jsonReq, function (err, data) {
        if (err) {
          return callback.onFailure(err);
        }
  
        if (typeof callback.inputVerificationCode === 'function') {
          return callback.inputVerificationCode(data);
        }
  
        return callback.onSuccess(data);
      });
    }
    /**
     * This is used to confirm a new password using a confirmationCode
     * @param {string} confirmationCode Code entered by user.
     * @param {string} newPassword Confirm new password.
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {onSuccess<void>} callback.onSuccess Called on success.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     */
    ;
  
    _proto.confirmPassword = function confirmPassword(confirmationCode, newPassword, callback, clientMetadata) {
      var jsonReq = {
        ClientId: this.pool.getClientId(),
        Username: this.username,
        ConfirmationCode: confirmationCode,
        Password: newPassword,
        ClientMetadata: clientMetadata
      };
  
      if (this.getUserContextData()) {
        jsonReq.UserContextData = this.getUserContextData();
      }
  
      this.client.request('ConfirmForgotPassword', jsonReq, function (err) {
        if (err) {
          return callback.onFailure(err);
        }
  
        return callback.onSuccess();
      });
    }
    /**
     * This is used to initiate an attribute confirmation request
     * @param {string} attributeName User attribute that needs confirmation.
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {inputVerificationCode} callback.inputVerificationCode Called on success.
     * @param {ClientMetadata} clientMetadata object which is passed from client to Cognito Lambda trigger
     * @returns {void}
     */
    ;
  
    _proto.getAttributeVerificationCode = function getAttributeVerificationCode(attributeName, callback, clientMetadata) {
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback.onFailure(new Error('User is not authenticated'));
      }
  
      this.client.request('GetUserAttributeVerificationCode', {
        AttributeName: attributeName,
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken(),
        ClientMetadata: clientMetadata
      }, function (err, data) {
        if (err) {
          return callback.onFailure(err);
        }
  
        if (typeof callback.inputVerificationCode === 'function') {
          return callback.inputVerificationCode(data);
        }
  
        return callback.onSuccess();
      });
      return undefined;
    }
    /**
     * This is used to confirm an attribute using a confirmation code
     * @param {string} attributeName Attribute being confirmed.
     * @param {string} confirmationCode Code entered by user.
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {onSuccess<string>} callback.onSuccess Called on success.
     * @returns {void}
     */
    ;
  
    _proto.verifyAttribute = function verifyAttribute(attributeName, confirmationCode, callback) {
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback.onFailure(new Error('User is not authenticated'));
      }
  
      this.client.request('VerifyUserAttribute', {
        AttributeName: attributeName,
        Code: confirmationCode,
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken()
      }, function (err) {
        if (err) {
          return callback.onFailure(err);
        }
  
        return callback.onSuccess('SUCCESS');
      });
      return undefined;
    }
    /**
     * This is used to get the device information using the current device key
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {onSuccess<*>} callback.onSuccess Called on success with device data.
     * @returns {void}
     */
    ;
  
    _proto.getDevice = function getDevice(callback) {
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback.onFailure(new Error('User is not authenticated'));
      }
  
      this.client.request('GetDevice', {
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken(),
        DeviceKey: this.deviceKey
      }, function (err, data) {
        if (err) {
          return callback.onFailure(err);
        }
  
        return callback.onSuccess(data);
      });
      return undefined;
    }
    /**
     * This is used to forget a specific device
     * @param {string} deviceKey Device key.
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {onSuccess<string>} callback.onSuccess Called on success.
     * @returns {void}
     */
    ;
  
    _proto.forgetSpecificDevice = function forgetSpecificDevice(deviceKey, callback) {
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback.onFailure(new Error('User is not authenticated'));
      }
  
      this.client.request('ForgetDevice', {
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken(),
        DeviceKey: deviceKey
      }, function (err) {
        if (err) {
          return callback.onFailure(err);
        }
  
        return callback.onSuccess('SUCCESS');
      });
      return undefined;
    }
    /**
     * This is used to forget the current device
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {onSuccess<string>} callback.onSuccess Called on success.
     * @returns {void}
     */
    ;
  
    _proto.forgetDevice = function forgetDevice(callback) {
      var _this15 = this;
  
      this.forgetSpecificDevice(this.deviceKey, {
        onFailure: callback.onFailure,
        onSuccess: function onSuccess(result) {
          _this15.deviceKey = null;
          _this15.deviceGroupKey = null;
          _this15.randomPassword = null;
  
          _this15.clearCachedDeviceKeyAndPassword();
  
          return callback.onSuccess(result);
        }
      });
    }
    /**
     * This is used to set the device status as remembered
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {onSuccess<string>} callback.onSuccess Called on success.
     * @returns {void}
     */
    ;
  
    _proto.setDeviceStatusRemembered = function setDeviceStatusRemembered(callback) {
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback.onFailure(new Error('User is not authenticated'));
      }
  
      this.client.request('UpdateDeviceStatus', {
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken(),
        DeviceKey: this.deviceKey,
        DeviceRememberedStatus: 'remembered'
      }, function (err) {
        if (err) {
          return callback.onFailure(err);
        }
  
        return callback.onSuccess('SUCCESS');
      });
      return undefined;
    }
    /**
     * This is used to set the device status as not remembered
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {onSuccess<string>} callback.onSuccess Called on success.
     * @returns {void}
     */
    ;
  
    _proto.setDeviceStatusNotRemembered = function setDeviceStatusNotRemembered(callback) {
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback.onFailure(new Error('User is not authenticated'));
      }
  
      this.client.request('UpdateDeviceStatus', {
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken(),
        DeviceKey: this.deviceKey,
        DeviceRememberedStatus: 'not_remembered'
      }, function (err) {
        if (err) {
          return callback.onFailure(err);
        }
  
        return callback.onSuccess('SUCCESS');
      });
      return undefined;
    }
    /**
     * This is used to list all devices for a user
     *
     * @param {int} limit the number of devices returned in a call
     * @param {string | null} paginationToken the pagination token in case any was returned before
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {onSuccess<*>} callback.onSuccess Called on success with device list.
     * @returns {void}
     */
    ;
  
    _proto.listDevices = function listDevices(limit, paginationToken, callback) {
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback.onFailure(new Error('User is not authenticated'));
      }
  
      var requestParams = {
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken(),
        Limit: limit
      };
  
      if (paginationToken) {
        requestParams.PaginationToken = paginationToken;
      }
  
      this.client.request('ListDevices', requestParams, function (err, data) {
        if (err) {
          return callback.onFailure(err);
        }
  
        return callback.onSuccess(data);
      });
      return undefined;
    }
    /**
     * This is used to globally revoke all tokens issued to a user
     * @param {object} callback Result callback map.
     * @param {onFailure} callback.onFailure Called on any error.
     * @param {onSuccess<string>} callback.onSuccess Called on success.
     * @returns {void}
     */
    ;
  
    _proto.globalSignOut = function globalSignOut(callback) {
      var _this16 = this;
  
      if (this.signInUserSession == null || !this.signInUserSession.isValid()) {
        return callback.onFailure(new Error('User is not authenticated'));
      }
  
      this.client.request('GlobalSignOut', {
        AccessToken: this.signInUserSession.getAccessToken().getJwtToken()
      }, function (err) {
        if (err) {
          return callback.onFailure(err);
        }
  
        _this16.clearCachedUser();
  
        return callback.onSuccess('SUCCESS');
      });
      return undefined;
    }
    /**
     * This is used for the user to signOut of the application and clear the cached tokens.
     * @returns {void}
     */
    ;
  
    _proto.signOut = function signOut() {
      this.signInUserSession = null;
      this.clearCachedUser();
    }
    /**
     * This is used by a user trying to select a given MFA
     * @param {string} answerChallenge the mfa the user wants
     * @param {nodeCallback<string>} callback Called on success or error.
     * @returns {void}
     */
    ;
  
    _proto.sendMFASelectionAnswer = function sendMFASelectionAnswer(answerChallenge, callback) {
      var _this17 = this;
  
      var challengeResponses = {};
      challengeResponses.USERNAME = this.username;
      challengeResponses.ANSWER = answerChallenge;
      var jsonReq = {
        ChallengeName: 'SELECT_MFA_TYPE',
        ChallengeResponses: challengeResponses,
        ClientId: this.pool.getClientId(),
        Session: this.Session
      };
  
      if (this.getUserContextData()) {
        jsonReq.UserContextData = this.getUserContextData();
      }
  
      this.client.request('RespondToAuthChallenge', jsonReq, function (err, data) {
        if (err) {
          return callback.onFailure(err);
        }
  
        _this17.Session = data.Session;
  
        if (answerChallenge === 'SMS_MFA') {
          return callback.mfaRequired(data.challengeName, data.challengeParameters);
        }
  
        if (answerChallenge === 'SOFTWARE_TOKEN_MFA') {
          return callback.totpRequired(data.challengeName, data.challengeParameters);
        }
  
        return undefined;
      });
    }
    /**
     * This returns the user context data for advanced security feature.
     * @returns {void}
     */
    ;
  
    _proto.getUserContextData = function getUserContextData() {
      var pool = this.pool;
      return pool.getUserContextData(this.username);
    }
    /**
     * This is used by an authenticated or a user trying to authenticate to associate a TOTP MFA
     * @param {nodeCallback<string>} callback Called on success or error.
     * @returns {void}
     */
    ;
  
    _proto.associateSoftwareToken = function associateSoftwareToken(callback) {
      var _this18 = this;
  
      if (!(this.signInUserSession != null && this.signInUserSession.isValid())) {
        this.client.request('AssociateSoftwareToken', {
          Session: this.Session
        }, function (err, data) {
          if (err) {
            return callback.onFailure(err);
          }
  
          _this18.Session = data.Session;
          return callback.associateSecretCode(data.SecretCode);
        });
      } else {
        this.client.request('AssociateSoftwareToken', {
          AccessToken: this.signInUserSession.getAccessToken().getJwtToken()
        }, function (err, data) {
          if (err) {
            return callback.onFailure(err);
          }
  
          return callback.associateSecretCode(data.SecretCode);
        });
      }
    }
    /**
     * This is used by an authenticated or a user trying to authenticate to verify a TOTP MFA
     * @param {string} totpCode The MFA code entered by the user.
     * @param {string} friendlyDeviceName The device name we are assigning to the device.
     * @param {nodeCallback<string>} callback Called on success or error.
     * @returns {void}
     */
    ;
  
    _proto.verifySoftwareToken = function verifySoftwareToken(totpCode, friendlyDeviceName, callback) {
      var _this19 = this;
  
      if (!(this.signInUserSession != null && this.signInUserSession.isValid())) {
        this.client.request('VerifySoftwareToken', {
          Session: this.Session,
          UserCode: totpCode,
          FriendlyDeviceName: friendlyDeviceName
        }, function (err, data) {
          if (err) {
            return callback.onFailure(err);
          }
  
          _this19.Session = data.Session;
          var challengeResponses = {};
          challengeResponses.USERNAME = _this19.username;
          var jsonReq = {
            ChallengeName: 'MFA_SETUP',
            ClientId: _this19.pool.getClientId(),
            ChallengeResponses: challengeResponses,
            Session: _this19.Session
          };
  
          if (_this19.getUserContextData()) {
            jsonReq.UserContextData = _this19.getUserContextData();
          }
  
          _this19.client.request('RespondToAuthChallenge', jsonReq, function (errRespond, dataRespond) {
            if (errRespond) {
              return callback.onFailure(errRespond);
            }
  
            _this19.signInUserSession = _this19.getCognitoUserSession(dataRespond.AuthenticationResult);
  
            _this19.cacheTokens();
  
            return callback.onSuccess(_this19.signInUserSession);
          });
  
          return undefined;
        });
      } else {
        this.client.request('VerifySoftwareToken', {
          AccessToken: this.signInUserSession.getAccessToken().getJwtToken(),
          UserCode: totpCode,
          FriendlyDeviceName: friendlyDeviceName
        }, function (err, data) {
          if (err) {
            return callback.onFailure(err);
          }
  
          return callback.onSuccess(data);
        });
      }
    };
  
    return CognitoUser;
  }();
  
  exports["default"] = CognitoUser;