UNPKG

amazon-cognito-identity-js

Version:

Amazon Cognito Identity Provider JavaScript SDK

1,355 lines (1,102 loc) • 68.8 kB
'use strict'; exports.__esModule = true; var _buffer = require('buffer/'); var _core = require('crypto-js/core'); var _core2 = _interopRequireDefault(_core); var _libTypedarrays = require('crypto-js/lib-typedarrays'); var _libTypedarrays2 = _interopRequireDefault(_libTypedarrays); var _encBase = require('crypto-js/enc-base64'); var _encBase2 = _interopRequireDefault(_encBase); var _hmacSha = require('crypto-js/hmac-sha256'); var _hmacSha2 = _interopRequireDefault(_hmacSha); var _BigInteger = require('./BigInteger'); var _BigInteger2 = _interopRequireDefault(_BigInteger); var _AuthenticationHelper = require('./AuthenticationHelper'); var _AuthenticationHelper2 = _interopRequireDefault(_AuthenticationHelper); var _CognitoAccessToken = require('./CognitoAccessToken'); var _CognitoAccessToken2 = _interopRequireDefault(_CognitoAccessToken); var _CognitoIdToken = require('./CognitoIdToken'); var _CognitoIdToken2 = _interopRequireDefault(_CognitoIdToken); var _CognitoRefreshToken = require('./CognitoRefreshToken'); var _CognitoRefreshToken2 = _interopRequireDefault(_CognitoRefreshToken); var _CognitoUserSession = require('./CognitoUserSession'); var _CognitoUserSession2 = _interopRequireDefault(_CognitoUserSession); var _DateHelper = require('./DateHelper'); var _DateHelper2 = _interopRequireDefault(_DateHelper); var _CognitoUserAttribute = require('./CognitoUserAttribute'); var _CognitoUserAttribute2 = _interopRequireDefault(_CognitoUserAttribute); var _StorageHelper = require('./StorageHelper'); var _StorageHelper2 = _interopRequireDefault(_StorageHelper); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /*! * 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. */ /** @class */ var CognitoUser = 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) { _classCallCheck(this, CognitoUser); 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 _StorageHelper2.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} */ CognitoUser.prototype.setSignInUserSession = function setSignInUserSession(signInUserSession) { this.clearCachedUserData(); this.signInUserSession = signInUserSession; this.cacheTokens(); }; /** * @returns {CognitoUserSession} the current session for this user */ CognitoUser.prototype.getSignInUserSession = function getSignInUserSession() { return this.signInUserSession; }; /** * @returns {string} the user's username */ CognitoUser.prototype.getUsername = function getUsername() { return this.username; }; /** * @returns {String} the authentication flow type */ CognitoUser.prototype.getAuthenticationFlowType = function getAuthenticationFlowType() { return this.authenticationFlowType; }; /** * sets authentication flow type * @param {string} authenticationFlowType New value. * @returns {void} */ CognitoUser.prototype.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} */ CognitoUser.prototype.initiateAuth = function initiateAuth(authDetails, callback) { var _this = this; var authParameters = authDetails.getAuthParameters(); authParameters.USERNAME = this.username; var jsonReq = { AuthFlow: 'CUSTOM_AUTH', ClientId: this.pool.getClientId(), AuthParameters: authParameters, ClientMetadata: authDetails.getValidationData() }; 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} */ CognitoUser.prototype.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} */ CognitoUser.prototype.authenticateUserDefaultAuth = function authenticateUserDefaultAuth(authDetails, callback) { var _this2 = this; var authenticationHelper = new _AuthenticationHelper2.default(this.pool.getUserPoolId().split('_')[1]); var dateHelper = new _DateHelper2.default(); var serverBValue = void 0; var salt = void 0; 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 jsonReq = { AuthFlow: _this2.authenticationFlowType, ClientId: _this2.pool.getClientId(), AuthParameters: authParameters, ClientMetadata: authDetails.getValidationData() }; 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 _BigInteger2.default(challengeParameters.SRP_B, 16); salt = new _BigInteger2.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 = _core2.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 = _core2.default.lib.WordArray.create(hkdf); var signatureString = _encBase2.default.stringify((0, _hmacSha2.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 }; 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} */ CognitoUser.prototype.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 _AuthenticationHelper2.default(this.pool.getUserPoolId().split('_')[1]); this.getCachedDeviceKeyAndPassword(); if (this.deviceKey != null) { authParameters.DEVICE_KEY = this.deviceKey; } var jsonReq = { AuthFlow: 'USER_PASSWORD_AUTH', ClientId: this.pool.getClientId(), AuthParameters: authParameters, ClientMetadata: authDetails.getValidationData() }; 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} */ CognitoUser.prototype.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: navigator.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. * @returns {void} */ CognitoUser.prototype.completeNewPasswordChallenge = function completeNewPasswordChallenge(newPassword, requiredAttributeData, callback) { var _this5 = this; if (!newPassword) { return callback.onFailure(new Error('New password is required.')); } var authenticationHelper = new _AuthenticationHelper2.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 }; 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. * @returns {void} * @private */ CognitoUser.prototype.getDeviceResponse = function getDeviceResponse(callback) { var _this6 = this; var authenticationHelper = new _AuthenticationHelper2.default(this.deviceGroupKey); var dateHelper = new _DateHelper2.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 }; 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 _BigInteger2.default(challengeParameters.SRP_B, 16); var salt = new _BigInteger2.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 = _core2.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 = _core2.default.lib.WordArray.create(hkdf); var signatureString = _encBase2.default.stringify((0, _hmacSha2.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. * @returns {void} */ CognitoUser.prototype.confirmRegistration = function confirmRegistration(confirmationCode, forceAliasCreation, callback) { var jsonReq = { ClientId: this.pool.getClientId(), ConfirmationCode: confirmationCode, Username: this.username, ForceAliasCreation: forceAliasCreation }; 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. * @returns {void} */ CognitoUser.prototype.sendCustomChallengeAnswer = function sendCustomChallengeAnswer(answerChallenge, callback) { var _this7 = this; var challengeResponses = {}; challengeResponses.USERNAME = this.username; challengeResponses.ANSWER = answerChallenge; var authenticationHelper = new _AuthenticationHelper2.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 }; 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. * @returns {void} */ CognitoUser.prototype.sendMFACode = function sendMFACode(confirmationCode, callback, mfaType) { 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 }; 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 _AuthenticationHelper2.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: navigator.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. * @returns {void} */ CognitoUser.prototype.changePassword = function changePassword(oldUserPassword, newUserPassword, callback) { 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() }, 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} */ CognitoUser.prototype.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} */ CognitoUser.prototype.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} */ CognitoUser.prototype.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. * @returns {void} */ CognitoUser.prototype.deleteUser = function deleteUser(callback) { 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() }, 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. * @returns {void} */ CognitoUser.prototype.updateAttributes = function updateAttributes(attributes, callback) { 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 }, function (err) { if (err) { return callback(err, null); } return callback(null, 'SUCCESS'); }); 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} */ CognitoUser.prototype.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 _CognitoUserAttribute2.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} */ CognitoUser.prototype.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; }; /** * This is used by an authenticated users to get the userData * @param {nodeCallback<UserData>} callback Called on success or error. * @returns {void} */ CognitoUser.prototype.getUserData = function getUserData(callback, params) { var _this10 = this; if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { this.clearCachedUserData(); return callback(new Error('User is not authenticated'), null); } var bypassCache = params ? params.bypassCache : false; var userData = this.storage.getItem(this.userDataKey); // get the cached user data if (!userData || bypassCache) { this.client.request('GetUser', { AccessToken: this.signInUserSession.getAccessToken().getJwtToken() }, function (err, latestUserData) { if (err) { return callback(err, null); } _this10.cacheUserData(latestUserData); var refresh = _this10.signInUserSession.getRefreshToken(); if (refresh && refresh.getToken()) { _this10.refreshSession(refresh, function (refreshError, data) { if (refreshError) { return callback(refreshError, null); } return callback(null, latestUserData); }); } else { return callback(null, latestUserData); } }); } else { try { return callback(null, JSON.parse(userData)); } catch (err) { this.clearCachedUserData(); return callback(err, null); } } return undefined; }; /** * 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} */ CognitoUser.prototype.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. * @returns {void} */ CognitoUser.prototype.resendConfirmationCode = function resendConfirmationCode(callback) { var jsonReq = { ClientId: this.pool.getClientId(), Username: this.username }; 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} */ CognitoUser.prototype.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 _CognitoIdToken2.default({ IdToken: this.storage.getItem(idTokenKey) }); var accessToken = new _CognitoAccessToken2.default({ AccessToken: this.storage.getItem(accessTokenKey) }); var refreshToken = new _CognitoRefreshToken2.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 _CognitoUserSession2.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. * @returns {void} */ CognitoUser.prototype.refreshSession = function refreshSession(refreshToken, callback) { var _this11 = 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 }; if (this.getUserContextData()) { jsonReq.UserContextData = this.getUserContextData(); } this.client.request('InitiateAuth', jsonReq, function (err, authResult) { if (err) { if (err.code === 'NotAuthorizedException') { _this11.clearCachedUser(); } return callback(err, null); } if (authResult) { var authenticationResult = authResult.AuthenticationResult; if (!Object.prototype.hasOwnProperty.call(authenticationResult, 'RefreshToken')) { authenticationResult.RefreshToken = refreshToken.getToken(); } _this11.signInUserSession = _this11.getCognitoUserSession(authenticationResult); _this11.cacheTokens(); return callback(null, _this11.signInUserSession); } return undefined; }); }; /** * This is used to save the session tokens to local storage * @returns {void} */ CognitoUser.prototype.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 */ CognitoUser.prototype.cacheUserData = function cacheUserData(userData) { this.storage.setItem(this.userDataKey, JSON.stringify(userData)); }; /** * This is to remove cached user data */ CognitoUser.prototype.clearCachedUserData = function clearCachedUserData() { this.storage.removeItem(this.userDataKey); }; CognitoUser.prototype.clearCachedUser = function clearCachedUser() { this.clearCachedTokens(); this.clearCachedUserData(); }; /** * This is used to cache the device key and device group and devic