"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _AnonymousUtils = _interopRequireDefault(require("./AnonymousUtils")); var _CoreManager = _interopRequireDefault(require("./CoreManager")); var _isRevocableSession = _interopRequireDefault(require("./isRevocableSession")); var _ParseError = _interopRequireDefault(require("./ParseError")); var _ParseObject = _interopRequireDefault(require("./ParseObject")); var _ParseSession = _interopRequireDefault(require("./ParseSession")); var _MoralisWeb = _interopRequireDefault(require("./MoralisWeb3")); var _Storage = _interopRequireDefault(require("./Storage")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Copyright (c) 2015-present, Parse, LLC. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @flow */ const CURRENT_USER_KEY = 'currentUser'; let canUseCurrentUser = !_CoreManager.default.get('IS_NODE'); let currentUserCacheMatchesDisk = false; let currentUserCache = null; const authProviders = {}; /** *
A Parse.User object is a local representation of a user persisted to the * Parse cloud. This class is a subclass of a Parse.Object, and retains the * same functionality of a Parse.Object, but also extends it with various * user specific methods, like authentication, signing up, and validation of * uniqueness.
* * @alias Parse.User * @augments Parse.Object */ class ParseUser extends _ParseObject.default { /** * @param {object} attributes The initial set of data to store in the user. */ constructor(attributes /*: ?AttributeMap*/ ) { super('_User'); if (attributes && typeof attributes === 'object') { if (!this.set(attributes || {})) { throw new Error("Can't create an invalid Parse User"); } } } /** * Request a revocable session token to replace the older style of token. * * @param {object} options * @returns {Promise} A promise that is resolved when the replacement * token has been fetched. */ _upgradeToRevocableSession(options /*: RequestOptions*/ ) /*: Promisecurrent
would return this user.
*
* @returns {boolean} true if user is cached on disk
*/
isCurrent()
/*: boolean*/
{
const current = ParseUser.current();
return !!current && current.id === this.id;
}
/**
* Returns get("username").
*
* @returns {string}
*/
getUsername()
/*: ?string*/
{
const username = this.get('username');
if (username == null || typeof username === 'string') {
return username;
}
return '';
}
/**
* Calls set("username", username, options) and returns the result.
*
* @param {string} username
*/
setUsername(username
/*: string*/
) {
// Strip anonymity, even we do not support anonymous user in js SDK, we may
// encounter anonymous user created by android/iOS in cloud code.
const authData = this.get('authData');
if (authData && typeof authData === 'object' && authData.hasOwnProperty('anonymous')) {
// We need to set anonymous to null instead of deleting it in order to remove it from Parse.
authData.anonymous = null;
}
this.set('username', username);
}
/**
* Calls set("password", password, options) and returns the result.
*
* @param {string} password User's Password
*/
setPassword(password
/*: string*/
) {
this.set('password', password);
}
/**
* Returns get("email").
*
* @returns {string} User's Email
*/
getEmail()
/*: ?string*/
{
const email = this.get('email');
if (email == null || typeof email === 'string') {
return email;
}
return '';
}
/**
* Calls set("email", email) and returns the result.
*
* @param {string} email
* @returns {boolean}
*/
setEmail(email
/*: string*/
) {
return this.set('email', email);
}
/**
* Returns the session token for this user, if the user has been logged in,
* or if it is the result of a query with the master key. Otherwise, returns
* undefined.
*
* @returns {string} the session token, or undefined
*/
getSessionToken()
/*: ?string*/
{
const token = this.get('sessionToken');
if (token == null || typeof token === 'string') {
return token;
}
return '';
}
/**
* Checks whether this user is the current user and has been authenticated.
*
* @returns {boolean} whether this user is the current user and is logged in.
*/
authenticated()
/*: boolean*/
{
const current = ParseUser.current();
return !!this.get('sessionToken') && !!current && current.id === this.id;
}
/**
* Signs up a new user. You should call this instead of save for
* new Parse.Users. This will create a new Parse.User on the server, and
* also persist the session on disk so that you can access the user using
* current
.
*
* A username and password must be set before calling signUp.
* * @param {object} attrs Extra fields to set on the new user, or null. * @param {object} options * @returns {Promise} A promise that is fulfilled when the signup * finishes. */ signUp(attrs /*: AttributeMap*/ , options /*:: ?: FullOptions*/ ) /*: Promisecurrent
.
*
* A username and password must be set before calling logIn.
* * @param {object} options * @returns {Promise} A promise that is fulfilled with the user when * the login is complete. */ logIn(options /*:: ?: FullOptions*/ ) /*: Promisecurrent
.
*
* @param {string} username The username (or email) to log in with.
* @param {string} password The password to log in with.
* @param {object} options
* @static
* @returns {Promise} A promise that is fulfilled with the user when
* the login completes.
*/
static logIn(username
/*: string*/
, password
/*: string*/
, options
/*:: ?: FullOptions*/
) {
if (typeof username !== 'string') {
return Promise.reject(new _ParseError.default(_ParseError.default.OTHER_CAUSE, 'Username must be a string.'));
}
if (typeof password !== 'string') {
return Promise.reject(new _ParseError.default(_ParseError.default.OTHER_CAUSE, 'Password must be a string.'));
}
const user = new this();
user._finishFetch({
username: username,
password: password
});
return user.logIn(options);
}
static loginOrSignup(username
/*: string*/
, password
/*: string*/
) {
return this.logIn(username, password).catch(err => {
if (err.code === 101) {
const newUser = new this();
newUser.set('username', username);
newUser.set('password', password);
return newUser.signUp();
}
throw err;
});
}
/**
* Logs in a user with a session token. On success, this saves the session
* to disk, so you can retrieve the currently logged in user using
* current
.
*
* @param {string} sessionToken The sessionToken to log in with.
* @param {object} options
* @static
* @returns {Promise} A promise that is fulfilled with the user when
* the login completes.
*/
static become(sessionToken
/*: string*/
, options
/*:: ?: RequestOptions*/
) {
if (!canUseCurrentUser) {
throw new Error('It is not memory-safe to become a user in a server environment');
}
options = options || {};
const becomeOptions
/*: RequestOptions*/
= {
sessionToken: sessionToken
};
if (options.hasOwnProperty('useMasterKey')) {
becomeOptions.useMasterKey = options.useMasterKey;
}
const controller = _CoreManager.default.getUserController();
const user = new this();
return controller.become(user, becomeOptions);
}
/**
* Retrieves a user with a session token.
*
* @param {string} sessionToken The sessionToken to get user with.
* @param {object} options
* @static
* @returns {Promise} A promise that is fulfilled with the user is fetched.
*/
static me(sessionToken
/*: string*/
, options
/*:: ?: RequestOptions*/
= {}) {
const controller = _CoreManager.default.getUserController();
const meOptions
/*: RequestOptions*/
= {
sessionToken: sessionToken
};
if (options.useMasterKey) {
meOptions.useMasterKey = options.useMasterKey;
}
const user = new this();
return controller.me(user, meOptions);
}
/**
* Logs in a user with a session token. On success, this saves the session
* to disk, so you can retrieve the currently logged in user using
* current
. If there is no session token the user will not logged in.
*
* @param {object} userJSON The JSON map of the User's data
* @static
* @returns {Promise} A promise that is fulfilled with the user when
* the login completes.
*/
static hydrate(userJSON
/*: AttributeMap*/
) {
const controller = _CoreManager.default.getUserController();
const user = new this();
return controller.hydrate(user, userJSON);
}
/**
* Static version of {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.User.html#linkWith linkWith}
*
* @param provider
* @param options
* @param saveOpts
* @static
* @returns {Promise}
*/
static logInWith(provider
/*: any*/
, options
/*: { authData?: AuthData }*/
, saveOpts
/*:: ?: FullOptions*/
)
/*: Promisecurrent
will return null
.
*
* @param {object} options
* @static
* @returns {Promise} A promise that is resolved when the session is
* destroyed on the server.
*/
static logOut(options
/*: RequestOptions*/
= {}) {
const controller = _CoreManager.default.getUserController();
return controller.logOut(options);
}
/**
* Requests a password reset email to be sent to the specified email address
* associated with the user account. This email allows the user to securely
* reset their password on the Parse site.
*
* @param {string} email The email address associated with the user that
* forgot their password.
* @param {object} options
* @static
* @returns {Promise}
*/
static requestPasswordReset(email
/*: string*/
, options
/*:: ?: RequestOptions*/
) {
options = options || {};
const requestOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
requestOptions.useMasterKey = options.useMasterKey;
}
const controller = _CoreManager.default.getUserController();
return controller.requestPasswordReset(email, requestOptions);
}
/**
* Request an email verification.
*
* @param {string} email The email address associated with the user that
* forgot their password.
* @param {object} options
* @static
* @returns {Promise}
*/
static requestEmailVerification(email
/*: string*/
, options
/*:: ?: RequestOptions*/
) {
options = options || {};
const requestOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
requestOptions.useMasterKey = options.useMasterKey;
}
const controller = _CoreManager.default.getUserController();
return controller.requestEmailVerification(email, requestOptions);
}
/**
* Verify whether a given password is the password of the current user.
*
* @param {string} username A username to be used for identificaiton
* @param {string} password A password to be verified
* @param {object} options
* @static
* @returns {Promise} A promise that is fulfilled with a user
* when the password is correct.
*/
static verifyPassword(username
/*: string*/
, password
/*: string*/
, options
/*:: ?: RequestOptions*/
) {
if (typeof username !== 'string') {
return Promise.reject(new _ParseError.default(_ParseError.default.OTHER_CAUSE, 'Username must be a string.'));
}
if (typeof password !== 'string') {
return Promise.reject(new _ParseError.default(_ParseError.default.OTHER_CAUSE, 'Password must be a string.'));
}
options = options || {};
const verificationOption = {};
if (options.hasOwnProperty('useMasterKey')) {
verificationOption.useMasterKey = options.useMasterKey;
}
const controller = _CoreManager.default.getUserController();
return controller.verifyPassword(username, password, verificationOption);
}
/**
* Allow someone to define a custom User class without className
* being rewritten to _User. The default behavior is to rewrite
* User to _User for legacy reasons. This allows developers to
* override that behavior.
*
* @param {boolean} isAllowed Whether or not to allow custom User class
* @static
*/
static allowCustomUserClass(isAllowed
/*: boolean*/
) {
_CoreManager.default.set('PERFORM_USER_REWRITE', !isAllowed);
}
/**
* Allows a legacy application to start using revocable sessions. If the
* current session token is not revocable, a request will be made for a new,
* revocable session.
* It is not necessary to call this method from cloud code unless you are
* handling user signup or login from the server side. In a cloud code call,
* this function will not attempt to upgrade the current token.
*
* @param {object} options
* @static
* @returns {Promise} A promise that is resolved when the process has
* completed. If a replacement session token is requested, the promise
* will be resolved after a new token has been fetched.
*/
static enableRevocableSession(options
/*:: ?: RequestOptions*/
) {
options = options || {};
_CoreManager.default.set('FORCE_REVOCABLE_SESSION', true);
if (canUseCurrentUser) {
const current = ParseUser.current();
if (current) {
return current._upgradeToRevocableSession(options);
}
}
return Promise.resolve();
}
/**
* Enables the use of become or the current user in a server
* environment. These features are disabled by default, since they depend on
* global objects that are not memory-safe for most servers.
*
* @static
*/
static enableUnsafeCurrentUser() {
canUseCurrentUser = true;
}
/**
* Disables the use of become or the current user in any environment.
* These features are disabled on servers by default, since they depend on
* global objects that are not memory-safe for most servers.
*
* @static
*/
static disableUnsafeCurrentUser() {
canUseCurrentUser = false;
}
/**
* When registering users with {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.User.html#linkWith linkWith} a basic auth provider
* is automatically created for you.
*
* For advanced authentication, you can register an Auth provider to
* implement custom authentication, deauthentication.
*
* @param provider
* @see {@link https://parseplatform.org/Parse-SDK-JS/api/master/AuthProvider.html AuthProvider}
* @see {@link https://docs.parseplatform.org/js/guide/#custom-authentication-module Custom Authentication Module}
* @static
*/
static _registerAuthenticationProvider(provider
/*: any*/
) {
authProviders[provider.getAuthType()] = provider; // Synchronize the current user with the auth provider.
ParseUser.currentAsync().then(current => {
if (current) {
current._synchronizeAuthData(provider.getAuthType());
}
});
}
/**
* @param provider
* @param options
* @param saveOpts
* @deprecated since 2.9.0 see {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.User.html#logInWith logInWith}
* @static
* @returns {Promise}
*/
static _logInWith(provider
/*: any*/
, options
/*: { authData?: AuthData }*/
, saveOpts
/*:: ?: FullOptions*/
) {
const user = new this();
return user.linkWith(provider, options, saveOpts);
}
static _clearCache() {
currentUserCache = null;
currentUserCacheMatchesDisk = false;
}
static _setCurrentUserCache(user
/*: ParseUser*/
) {
currentUserCache = user;
}
}
_ParseObject.default.registerSubclass('_User', ParseUser);
const DefaultController = {
updateUserOnDisk(user) {
const path = _Storage.default.generatePath(CURRENT_USER_KEY);
const json = user.toJSON();
delete json.password;
json.className = '_User';
let userData = JSON.stringify(json);
if (_CoreManager.default.get('ENCRYPTED_USER')) {
const crypto = _CoreManager.default.getCryptoController();
userData = crypto.encrypt(json, _CoreManager.default.get('ENCRYPTED_KEY'));
}
return _Storage.default.setItemAsync(path, userData).then(() => {
return user;
});
},
removeUserFromDisk() {
const path = _Storage.default.generatePath(CURRENT_USER_KEY);
currentUserCacheMatchesDisk = true;
currentUserCache = null;
return _Storage.default.removeItemAsync(path);
},
async setCurrentUser(user) {
const currentUser = await this.currentUserAsync();
if (currentUser && !user.equals(currentUser) && _AnonymousUtils.default.isLinked(currentUser)) {
await currentUser.destroy({
sessionToken: currentUser.getSessionToken()
});
}
currentUserCache = user;
user._cleanupAuthData();
user._synchronizeAllAuthData();
return DefaultController.updateUserOnDisk(user);
},
currentUser()
/*: ?ParseUser*/
{
if (currentUserCache) {
return currentUserCache;
}
if (currentUserCacheMatchesDisk) {
return null;
}
if (_Storage.default.async()) {
throw new Error('Cannot call currentUser() when using a platform with an async ' + 'storage system. Call currentUserAsync() instead.');
}
const path = _Storage.default.generatePath(CURRENT_USER_KEY);
let userData = _Storage.default.getItem(path);
currentUserCacheMatchesDisk = true;
if (!userData) {
currentUserCache = null;
return null;
}
if (_CoreManager.default.get('ENCRYPTED_USER')) {
const crypto = _CoreManager.default.getCryptoController();
userData = crypto.decrypt(userData, _CoreManager.default.get('ENCRYPTED_KEY'));
}
userData = JSON.parse(userData);
if (!userData.className) {
userData.className = '_User';
}
if (userData._id) {
if (userData.objectId !== userData._id) {
userData.objectId = userData._id;
}
delete userData._id;
}
if (userData._sessionToken) {
userData.sessionToken = userData._sessionToken;
delete userData._sessionToken;
}
const current = _ParseObject.default.fromJSON(userData);
currentUserCache = current;
current._synchronizeAllAuthData();
return current;
},
currentUserAsync()
/*: Promise*/
{
if (currentUserCache) {
return Promise.resolve(currentUserCache);
}
if (currentUserCacheMatchesDisk) {
return Promise.resolve(null);
}
const path = _Storage.default.generatePath(CURRENT_USER_KEY);
return _Storage.default.getItemAsync(path).then(userData => {
currentUserCacheMatchesDisk = true;
if (!userData) {
currentUserCache = null;
return Promise.resolve(null);
}
if (_CoreManager.default.get('ENCRYPTED_USER')) {
const crypto = _CoreManager.default.getCryptoController();
userData = crypto.decrypt(userData.toString(), _CoreManager.default.get('ENCRYPTED_KEY'));
}
userData = JSON.parse(userData);
if (!userData.className) {
userData.className = '_User';
}
if (userData._id) {
if (userData.objectId !== userData._id) {
userData.objectId = userData._id;
}
delete userData._id;
}
if (userData._sessionToken) {
userData.sessionToken = userData._sessionToken;
delete userData._sessionToken;
}
const current = _ParseObject.default.fromJSON(userData);
currentUserCache = current;
current._synchronizeAllAuthData();
return Promise.resolve(current);
});
},
signUp(user
/*: ParseUser*/
, attrs
/*: AttributeMap*/
, options
/*: RequestOptions*/
)
/*: Promise