Advertisement
Guest User

Untitled

a guest
Jun 30th, 2016
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 29.13 KB | None | 0 0
  1. /**
  2. * Copyright (c) 2015-present, Parse, LLC.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. * @flow
  10. */
  11.  
  12. import CoreManager from './CoreManager';
  13. import isRevocableSession from './isRevocableSession';
  14. import ParseError from './ParseError';
  15. import ParseObject from './ParseObject';
  16. import ParsePromise from './ParsePromise';
  17. import ParseSession from './ParseSession';
  18. import Storage from './Storage';
  19.  
  20. import type { AttributeMap } from './ObjectStateMutations';
  21. import type { RequestOptions, FullOptions } from './RESTController';
  22.  
  23. export type AuthData = ?{ [key: string]: mixed };
  24.  
  25. var CURRENT_USER_KEY = 'currentUser';
  26. var canUseCurrentUser = !CoreManager.get('IS_NODE');
  27. var currentUserCacheMatchesDisk = false;
  28. var currentUserCache = null;
  29.  
  30. var authProviders = {};
  31.  
  32. /**
  33. * @class Parse.User
  34. * @constructor
  35. *
  36. * <p>A Parse.User object is a local representation of a user persisted to the
  37. * Parse cloud. This class is a subclass of a Parse.Object, and retains the
  38. * same functionality of a Parse.Object, but also extends it with various
  39. * user specific methods, like authentication, signing up, and validation of
  40. * uniqueness.</p>
  41. */
  42. export default class ParseUser extends ParseObject {
  43. constructor(attributes: ?AttributeMap) {
  44. super('_User');
  45. if (attributes && typeof attributes === 'object'){
  46. if (!this.set(attributes || {})) {
  47. throw new Error('Can\'t create an invalid Parse User');
  48. }
  49. }
  50. }
  51.  
  52. /**
  53. * Request a revocable session token to replace the older style of token.
  54. * @method _upgradeToRevocableSession
  55. * @param {Object} options A Backbone-style options object.
  56. * @return {Parse.Promise} A promise that is resolved when the replacement
  57. * token has been fetched.
  58. */
  59. _upgradeToRevocableSession(options: RequestOptions): ParsePromise {
  60. options = options || {};
  61.  
  62. var upgradeOptions = {};
  63. if (options.hasOwnProperty('useMasterKey')) {
  64. upgradeOptions.useMasterKey = options.useMasterKey;
  65. }
  66.  
  67. var controller = CoreManager.getUserController();
  68. return controller.upgradeToRevocableSession(
  69. this,
  70. upgradeOptions
  71. )._thenRunCallbacks(options);
  72. }
  73.  
  74. /**
  75. * Unlike in the Android/iOS SDKs, logInWith is unnecessary, since you can
  76. * call linkWith on the user (even if it doesn't exist yet on the server).
  77. * @method _linkWith
  78. */
  79. _linkWith(provider, options: { authData?: AuthData }): ParsePromise {
  80. var authType;
  81. if (typeof provider === 'string') {
  82. authType = provider;
  83. provider = authProviders[provider];
  84. } else {
  85. authType = provider.getAuthType();
  86. }
  87. if (options && options.hasOwnProperty('authData')) {
  88. var authData = this.get('authData') || {};
  89. authData[authType] = options.authData;
  90.  
  91. var controller = CoreManager.getUserController();
  92. return controller.linkWith(
  93. this,
  94. authData
  95. )._thenRunCallbacks(options, this);
  96. } else {
  97. var promise = new ParsePromise();
  98. provider.authenticate({
  99. success: (provider, result) => {
  100. var opts = {};
  101. opts.authData = result;
  102. if (options.success) {
  103. opts.success = options.success;
  104. }
  105. if (options.error) {
  106. opts.error = options.error;
  107. }
  108. this._linkWith(provider, opts).then(() => {
  109. promise.resolve(this);
  110. }, (error) => {
  111. promise.reject(error);
  112. });
  113. },
  114. error: (provider, error) => {
  115. if (options.error) {
  116. options.error(this, error);
  117. }
  118. promise.reject(error);
  119. }
  120. });
  121. return promise;
  122. }
  123. }
  124.  
  125. /**
  126. * Synchronizes auth data for a provider (e.g. puts the access token in the
  127. * right place to be used by the Facebook SDK).
  128. * @method _synchronizeAuthData
  129. */
  130. _synchronizeAuthData(provider: string) {
  131. if (!this.isCurrent() || !provider) {
  132. return;
  133. }
  134. var authType;
  135. if (typeof provider === 'string') {
  136. authType = provider;
  137. provider = authProviders[authType];
  138. } else {
  139. authType = provider.getAuthType();
  140. }
  141. var authData = this.get('authData');
  142. if (!provider || typeof authData !== 'object') {
  143. return;
  144. }
  145. var success = provider.restoreAuthentication(authData[authType]);
  146. if (!success) {
  147. this._unlinkFrom(provider);
  148. }
  149. }
  150.  
  151. /**
  152. * Synchronizes authData for all providers.
  153. * @method _synchronizeAllAuthData
  154. */
  155. _synchronizeAllAuthData() {
  156. var authData = this.get('authData');
  157. if (typeof authData !== 'object') {
  158. return;
  159. }
  160.  
  161. for (var key in authData) {
  162. this._synchronizeAuthData(key);
  163. }
  164. }
  165.  
  166. /**
  167. * Removes null values from authData (which exist temporarily for
  168. * unlinking)
  169. * @method _cleanupAuthData
  170. */
  171. _cleanupAuthData() {
  172. if (!this.isCurrent()) {
  173. return;
  174. }
  175. var authData = this.get('authData');
  176. if (typeof authData !== 'object') {
  177. return;
  178. }
  179.  
  180. for (var key in authData) {
  181. if (!authData[key]) {
  182. delete authData[key];
  183. }
  184. }
  185. }
  186.  
  187. /**
  188. * Unlinks a user from a service.
  189. * @method _unlinkFrom
  190. */
  191. _unlinkFrom(provider, options?: FullOptions) {
  192. var authType;
  193. if (typeof provider === 'string') {
  194. authType = provider;
  195. provider = authProviders[provider];
  196. } else {
  197. authType = provider.getAuthType();
  198. }
  199. return this._linkWith(provider, { authData: null }).then(() => {
  200. this._synchronizeAuthData(provider);
  201. return ParsePromise.as(this);
  202. })._thenRunCallbacks(options);
  203. }
  204.  
  205. /**
  206. * Checks whether a user is linked to a service.
  207. * @method _isLinked
  208. */
  209. _isLinked(provider): boolean {
  210. var authType;
  211. if (typeof provider === 'string') {
  212. authType = provider;
  213. } else {
  214. authType = provider.getAuthType();
  215. }
  216. var authData = this.get('authData') || {};
  217. return !!authData[authType];
  218. }
  219.  
  220. /**
  221. * Deauthenticates all providers.
  222. * @method _logOutWithAll
  223. */
  224. _logOutWithAll() {
  225. var authData = this.get('authData');
  226. if (typeof authData !== 'object') {
  227. return;
  228. }
  229.  
  230. for (var key in authData) {
  231. this._logOutWith(key);
  232. }
  233. }
  234.  
  235. /**
  236. * Deauthenticates a single provider (e.g. removing access tokens from the
  237. * Facebook SDK).
  238. * @method _logOutWith
  239. */
  240. _logOutWith(provider) {
  241. if (!this.isCurrent()) {
  242. return;
  243. }
  244. if (typeof provider === 'string') {
  245. provider = authProviders[provider];
  246. }
  247. if (provider && provider.deauthenticate) {
  248. provider.deauthenticate();
  249. }
  250. }
  251.  
  252. /**
  253. * Class instance method used to maintain specific keys when a fetch occurs.
  254. * Used to ensure that the session token is not lost.
  255. */
  256. _preserveFieldsOnFetch(): AttributeMap {
  257. return {
  258. sessionToken: this.get('sessionToken'),
  259. };
  260. }
  261.  
  262. /**
  263. * Returns true if <code>current</code> would return this user.
  264. * @method isCurrent
  265. * @return {Boolean}
  266. */
  267. isCurrent(): boolean {
  268. var current = ParseUser.current();
  269. return !!current && current.id === this.id;
  270. }
  271.  
  272. /**
  273. * Returns get("username").
  274. * @method getUsername
  275. * @return {String}
  276. */
  277. getUsername(): ?string {
  278. return this.get('username');
  279. }
  280.  
  281. /**
  282. * Calls set("username", username, options) and returns the result.
  283. * @method setUsername
  284. * @param {String} username
  285. * @param {Object} options A Backbone-style options object.
  286. * @return {Boolean}
  287. */
  288. setUsername(username: string) {
  289. // Strip anonymity, even we do not support anonymous user in js SDK, we may
  290. // encounter anonymous user created by android/iOS in cloud code.
  291. var authData = this.get('authData');
  292. if (authData && authData.hasOwnProperty('anonymous')) {
  293. // We need to set anonymous to null instead of deleting it in order to remove it from Parse.
  294. authData.anonymous = null;
  295. }
  296. this.set('username', username);
  297. }
  298.  
  299. /**
  300. * Calls set("password", password, options) and returns the result.
  301. * @method setPassword
  302. * @param {String} password
  303. * @param {Object} options A Backbone-style options object.
  304. * @return {Boolean}
  305. */
  306. setPassword(password: string) {
  307. this.set('password', password);
  308. }
  309.  
  310. /**
  311. * Returns get("email").
  312. * @method getEmail
  313. * @return {String}
  314. */
  315. getEmail(): ?string {
  316. return this.get('email');
  317. }
  318.  
  319. /**
  320. * Calls set("email", email, options) and returns the result.
  321. * @method setEmail
  322. * @param {String} email
  323. * @param {Object} options A Backbone-style options object.
  324. * @return {Boolean}
  325. */
  326. setEmail(email: string) {
  327. this.set('email', email);
  328. }
  329.  
  330. /**
  331. * Returns the session token for this user, if the user has been logged in,
  332. * or if it is the result of a query with the master key. Otherwise, returns
  333. * undefined.
  334. * @method getSessionToken
  335. * @return {String} the session token, or undefined
  336. */
  337. getSessionToken(): ?string {
  338. return this.get('sessionToken');
  339. }
  340.  
  341. /**
  342. * Checks whether this user is the current user and has been authenticated.
  343. * @method authenticated
  344. * @return (Boolean) whether this user is the current user and is logged in.
  345. */
  346. authenticated(): boolean {
  347. var current = ParseUser.current();
  348. return (
  349. !!this.get('sessionToken') &&
  350. !!current &&
  351. current.id === this.id
  352. );
  353. }
  354.  
  355. /**
  356. * Signs up a new user. You should call this instead of save for
  357. * new Parse.Users. This will create a new Parse.User on the server, and
  358. * also persist the session on disk so that you can access the user using
  359. * <code>current</code>.
  360. *
  361. * <p>A username and password must be set before calling signUp.</p>
  362. *
  363. * <p>Calls options.success or options.error on completion.</p>
  364. *
  365. * @method signUp
  366. * @param {Object} attrs Extra fields to set on the new user, or null.
  367. * @param {Object} options A Backbone-style options object.
  368. * @return {Parse.Promise} A promise that is fulfilled when the signup
  369. * finishes.
  370. */
  371. signUp(attrs: AttributeMap, options: FullOptions): ParsePromise {
  372. options = options || {};
  373.  
  374. var signupOptions = {};
  375. if (options.hasOwnProperty('useMasterKey')) {
  376. signupOptions.useMasterKey = options.useMasterKey;
  377. }
  378. if (options.hasOwnProperty('installationId')) {
  379. signupOptions.installationId = options.installationId;
  380. }
  381.  
  382. var controller = CoreManager.getUserController();
  383. return controller.signUp(
  384. this,
  385. attrs,
  386. signupOptions
  387. )._thenRunCallbacks(options, this);
  388. }
  389.  
  390. /**
  391. * Logs in a Parse.User. On success, this saves the session to disk,
  392. * so you can retrieve the currently logged in user using
  393. * <code>current</code>.
  394. *
  395. * <p>A username and password must be set before calling logIn.</p>
  396. *
  397. * <p>Calls options.success or options.error on completion.</p>
  398. *
  399. * @method logIn
  400. * @param {Object} options A Backbone-style options object.
  401. * @return {Parse.Promise} A promise that is fulfilled with the user when
  402. * the login is complete.
  403. */
  404. logIn(options: FullOptions): ParsePromise {
  405. options = options || {};
  406.  
  407. var loginOptions = {};
  408. if (options.hasOwnProperty('useMasterKey')) {
  409. loginOptions.useMasterKey = options.useMasterKey;
  410. }
  411. if (options.hasOwnProperty('installationId')) {
  412. loginOptions.installationId = options.installationId;
  413. }
  414.  
  415. var controller = CoreManager.getUserController();
  416. return controller.logIn(this, loginOptions)._thenRunCallbacks(options, this);
  417. }
  418.  
  419. /**
  420. * Wrap the default save behavior with functionality to save to local
  421. * storage if this is current user.
  422. */
  423. save(...args: Array<any>): ParsePromise {
  424. return super.save.apply(this, args).then(() => {
  425. if (this.isCurrent()) {
  426. return CoreManager.getUserController().updateUserOnDisk(this);
  427. }
  428. return this;
  429. });
  430. }
  431.  
  432. /**
  433. * Wrap the default destroy behavior with functionality that logs out
  434. * the current user when it is destroyed
  435. */
  436. destroy(...args: Array<any>): ParsePromise {
  437. return super.destroy.apply(this, args).then(() => {
  438. if (this.isCurrent()) {
  439. return CoreManager.getUserController().removeUserFromDisk();
  440. }
  441. return this;
  442. });
  443. }
  444.  
  445. /**
  446. * Wrap the default fetch behavior with functionality to save to local
  447. * storage if this is current user.
  448. */
  449. fetch(...args: Array<any>): ParsePromise {
  450. return super.fetch.apply(this, args).then(() => {
  451. if (this.isCurrent()) {
  452. return CoreManager.getUserController().updateUserOnDisk(this);
  453. }
  454. return this;
  455. });
  456. }
  457.  
  458. static readOnlyAttributes() {
  459. return ['sessionToken'];
  460. }
  461.  
  462. /**
  463. * Adds functionality to the existing Parse.User class
  464. * @method extend
  465. * @param {Object} protoProps A set of properties to add to the prototype
  466. * @param {Object} classProps A set of static properties to add to the class
  467. * @static
  468. * @return {Class} The newly extended Parse.User class
  469. */
  470. static extend(protoProps, classProps) {
  471. if (protoProps) {
  472. for (var prop in protoProps) {
  473. if (prop !== 'className') {
  474. Object.defineProperty(ParseUser.prototype, prop, {
  475. value: protoProps[prop],
  476. enumerable: false,
  477. writable: true,
  478. configurable: true
  479. });
  480. }
  481. }
  482. }
  483.  
  484. if (classProps) {
  485. for (var prop in classProps) {
  486. if (prop !== 'className') {
  487. Object.defineProperty(ParseUser, prop, {
  488. value: classProps[prop],
  489. enumerable: false,
  490. writable: true,
  491. configurable: true
  492. });
  493. }
  494. }
  495. }
  496.  
  497. return ParseUser;
  498. }
  499.  
  500. /**
  501. * Retrieves the currently logged in ParseUser with a valid session,
  502. * either from memory or localStorage, if necessary.
  503. * @method current
  504. * @static
  505. * @return {Parse.Object} The currently logged in Parse.User.
  506. */
  507. static current(): ?ParseUser {
  508. if (!canUseCurrentUser) {
  509. return null;
  510. }
  511. var controller = CoreManager.getUserController();
  512. return controller.currentUser();
  513. }
  514.  
  515. /**
  516. * Retrieves the currently logged in ParseUser from asynchronous Storage.
  517. * @method currentAsync
  518. * @static
  519. * @return {Parse.Promise} A Promise that is resolved with the currently
  520. * logged in Parse User
  521. */
  522. static currentAsync(): ParsePromise {
  523. if (!canUseCurrentUser) {
  524. return ParsePromise.as(null);
  525. }
  526. var controller = CoreManager.getUserController();
  527. return controller.currentUserAsync();
  528. }
  529.  
  530. /**
  531. * Signs up a new user with a username (or email) and password.
  532. * This will create a new Parse.User on the server, and also persist the
  533. * session in localStorage so that you can access the user using
  534. * {@link #current}.
  535. *
  536. * <p>Calls options.success or options.error on completion.</p>
  537. *
  538. * @method signUp
  539. * @param {String} username The username (or email) to sign up with.
  540. * @param {String} password The password to sign up with.
  541. * @param {Object} attrs Extra fields to set on the new user.
  542. * @param {Object} options A Backbone-style options object.
  543. * @static
  544. * @return {Parse.Promise} A promise that is fulfilled with the user when
  545. * the signup completes.
  546. */
  547. static signUp(username, password, attrs, options) {
  548. attrs = attrs || {};
  549. attrs.username = username;
  550. attrs.password = password;
  551. var user = new ParseUser(attrs);
  552. return user.signUp({}, options);
  553. }
  554.  
  555. /**
  556. * Logs in a user with a username (or email) and password. On success, this
  557. * saves the session to disk, so you can retrieve the currently logged in
  558. * user using <code>current</code>.
  559. *
  560. * <p>Calls options.success or options.error on completion.</p>
  561. *
  562. * @method logIn
  563. * @param {String} username The username (or email) to log in with.
  564. * @param {String} password The password to log in with.
  565. * @param {Object} options A Backbone-style options object.
  566. * @static
  567. * @return {Parse.Promise} A promise that is fulfilled with the user when
  568. * the login completes.
  569. */
  570. static logIn(username, password, options) {
  571. if (typeof username !== 'string') {
  572. return ParsePromise.error(
  573. new ParseError(
  574. ParseError.OTHER_CAUSE,
  575. 'Username must be a string.'
  576. )
  577. );
  578. } else if (typeof password !== 'string') {
  579. return ParsePromise.error(
  580. new ParseError(
  581. ParseError.OTHER_CAUSE,
  582. 'Password must be a string.'
  583. )
  584. );
  585. }
  586. var user = new ParseUser();
  587. user._finishFetch({ username: username, password: password });
  588. return user.logIn(options);
  589. }
  590.  
  591. /**
  592. * Logs in a user with a session token. On success, this saves the session
  593. * to disk, so you can retrieve the currently logged in user using
  594. * <code>current</code>.
  595. *
  596. * <p>Calls options.success or options.error on completion.</p>
  597. *
  598. * @method become
  599. * @param {String} sessionToken The sessionToken to log in with.
  600. * @param {Object} options A Backbone-style options object.
  601. * @static
  602. * @return {Parse.Promise} A promise that is fulfilled with the user when
  603. * the login completes.
  604. */
  605. static become(sessionToken, options) {
  606. if (!canUseCurrentUser) {
  607. throw new Error(
  608. 'It is not memory-safe to become a user in a server environment'
  609. );
  610. }
  611. options = options || {};
  612.  
  613. var becomeOptions: RequestOptions = {
  614. sessionToken: sessionToken
  615. };
  616. if (options.hasOwnProperty('useMasterKey')) {
  617. becomeOptions.useMasterKey = options.useMasterKey;
  618. }
  619.  
  620. var controller = CoreManager.getUserController();
  621. return controller.become(becomeOptions)._thenRunCallbacks(options);
  622. }
  623.  
  624. static logInWith(provider, options) {
  625. return ParseUser._logInWith(provider, options);
  626. }
  627.  
  628. /**
  629. * Logs out the currently logged in user session. This will remove the
  630. * session from disk, log out of linked services, and future calls to
  631. * <code>current</code> will return <code>null</code>.
  632. * @method logOut
  633. * @static
  634. * @return {Parse.Promise} A promise that is resolved when the session is
  635. * destroyed on the server.
  636. */
  637. static logOut() {
  638. if (!canUseCurrentUser) {
  639. throw new Error(
  640. 'There is no current user user on a node.js server environment.'
  641. );
  642. }
  643.  
  644. var controller = CoreManager.getUserController();
  645. return controller.logOut();
  646. }
  647.  
  648. /**
  649. * Requests a password reset email to be sent to the specified email address
  650. * associated with the user account. This email allows the user to securely
  651. * reset their password on the Parse site.
  652. *
  653. * <p>Calls options.success or options.error on completion.</p>
  654. *
  655. * @method requestPasswordReset
  656. * @param {String} email The email address associated with the user that
  657. * forgot their password.
  658. * @param {Object} options A Backbone-style options object.
  659. * @static
  660. */
  661. static requestPasswordReset(email, options) {
  662. options = options || {};
  663.  
  664. var requestOptions = {};
  665. if (options.hasOwnProperty('useMasterKey')) {
  666. requestOptions.useMasterKey = options.useMasterKey;
  667. }
  668.  
  669. var controller = CoreManager.getUserController();
  670. return controller.requestPasswordReset(
  671. email, requestOptions
  672. )._thenRunCallbacks(options);
  673. }
  674.  
  675. /**
  676. * Allow someone to define a custom User class without className
  677. * being rewritten to _User. The default behavior is to rewrite
  678. * User to _User for legacy reasons. This allows developers to
  679. * override that behavior.
  680. *
  681. * @method allowCustomUserClass
  682. * @param {Boolean} isAllowed Whether or not to allow custom User class
  683. * @static
  684. */
  685. static allowCustomUserClass(isAllowed: boolean) {
  686. CoreManager.set('PERFORM_USER_REWRITE', !isAllowed);
  687. }
  688.  
  689. /**
  690. * Allows a legacy application to start using revocable sessions. If the
  691. * current session token is not revocable, a request will be made for a new,
  692. * revocable session.
  693. * It is not necessary to call this method from cloud code unless you are
  694. * handling user signup or login from the server side. In a cloud code call,
  695. * this function will not attempt to upgrade the current token.
  696. * @method enableRevocableSession
  697. * @param {Object} options A Backbone-style options object.
  698. * @static
  699. * @return {Parse.Promise} A promise that is resolved when the process has
  700. * completed. If a replacement session token is requested, the promise
  701. * will be resolved after a new token has been fetched.
  702. */
  703. static enableRevocableSession(options) {
  704. options = options || {};
  705. CoreManager.set('FORCE_REVOCABLE_SESSION', true);
  706. if (canUseCurrentUser) {
  707. var current = ParseUser.current();
  708. if (current) {
  709. return current._upgradeToRevocableSession(options);
  710. }
  711. }
  712. return ParsePromise.as()._thenRunCallbacks(options);
  713. }
  714.  
  715. /**
  716. * Enables the use of become or the current user in a server
  717. * environment. These features are disabled by default, since they depend on
  718. * global objects that are not memory-safe for most servers.
  719. * @method enableUnsafeCurrentUser
  720. * @static
  721. */
  722. static enableUnsafeCurrentUser() {
  723. canUseCurrentUser = true;
  724. }
  725.  
  726. /**
  727. * Disables the use of become or the current user in any environment.
  728. * These features are disabled on servers by default, since they depend on
  729. * global objects that are not memory-safe for most servers.
  730. * @method disableUnsafeCurrentUser
  731. * @static
  732. */
  733. static disableUnsafeCurrentUser() {
  734. canUseCurrentUser = false;
  735. }
  736.  
  737. static _registerAuthenticationProvider(provider) {
  738. authProviders[provider.getAuthType()] = provider;
  739. // Synchronize the current user with the auth provider.
  740. ParseUser.currentAsync().then((current) => {
  741. if (current) {
  742. current._synchronizeAuthData(provider.getAuthType());
  743. }
  744. });
  745. }
  746.  
  747. static _logInWith(provider, options) {
  748. var user = new ParseUser();
  749. return user._linkWith(provider, options);
  750. }
  751.  
  752. static _clearCache() {
  753. currentUserCache = null;
  754. currentUserCacheMatchesDisk = false;
  755. }
  756.  
  757. static _setCurrentUserCache(user) {
  758. currentUserCache = user;
  759. }
  760. }
  761.  
  762. ParseObject.registerSubclass('_User', ParseUser);
  763.  
  764. var DefaultController = {
  765. updateUserOnDisk(user) {
  766. var path = Storage.generatePath(CURRENT_USER_KEY);
  767. var json = user.toJSON();
  768. json.className = '_User';
  769. return Storage.setItemAsync(
  770. path, JSON.stringify(json)
  771. ).then(() => {
  772. return user;
  773. });
  774. },
  775.  
  776. removeUserFromDisk() {
  777. let path = Storage.generatePath(CURRENT_USER_KEY);
  778. currentUserCacheMatchesDisk = true;
  779. currentUserCache = null;
  780. return Storage.removeItemAsync(path);
  781. },
  782.  
  783. setCurrentUser(user) {
  784. currentUserCache = user;
  785. user._cleanupAuthData();
  786. user._synchronizeAllAuthData();
  787. return DefaultController.updateUserOnDisk(user);
  788. },
  789.  
  790. currentUser(): ?ParseUser {
  791. if (currentUserCache) {
  792. return currentUserCache;
  793. }
  794. if (currentUserCacheMatchesDisk) {
  795. return null;
  796. }
  797. if (Storage.async()) {
  798. throw new Error(
  799. 'Cannot call currentUser() when using a platform with an async ' +
  800. 'storage system. Call currentUserAsync() instead.'
  801. );
  802. }
  803. var path = Storage.generatePath(CURRENT_USER_KEY);
  804. var userData = Storage.getItem(path);
  805. currentUserCacheMatchesDisk = true;
  806. if (!userData) {
  807. currentUserCache = null;
  808. return null;
  809. }
  810. userData = JSON.parse(userData);
  811. if (!userData.className) {
  812. userData.className = '_User';
  813. }
  814. if (userData._id) {
  815. if (userData.objectId !== userData._id) {
  816. userData.objectId = userData._id;
  817. }
  818. delete userData._id;
  819. }
  820. if (userData._sessionToken) {
  821. userData.sessionToken = userData._sessionToken;
  822. delete userData._sessionToken;
  823. }
  824. var current = ParseObject.fromJSON(userData);
  825. currentUserCache = current;
  826. current._synchronizeAllAuthData();
  827. return current;
  828. },
  829.  
  830. currentUserAsync(): ParsePromise {
  831. if (currentUserCache) {
  832. return ParsePromise.as(currentUserCache)
  833. }
  834. if (currentUserCacheMatchesDisk) {
  835. return ParsePromise.as(null);
  836. }
  837. var path = Storage.generatePath(CURRENT_USER_KEY);
  838. return Storage.getItemAsync(
  839. path
  840. ).then((userData) => {
  841. currentUserCacheMatchesDisk = true;
  842. if (!userData) {
  843. currentUserCache = null;
  844. return ParsePromise.as(null);
  845. }
  846. userData = JSON.parse(userData);
  847. if (!userData.className) {
  848. userData.className = '_User';
  849. }
  850. if (userData._id) {
  851. if (userData.objectId !== userData._id) {
  852. userData.objectId = userData._id;
  853. }
  854. delete userData._id;
  855. }
  856. if (userData._sessionToken) {
  857. userData.sessionToken = userData._sessionToken;
  858. delete userData._sessionToken;
  859. }
  860. var current = ParseObject.fromJSON(userData);
  861. currentUserCache = current;
  862. current._synchronizeAllAuthData();
  863. return ParsePromise.as(current);
  864. });
  865. },
  866.  
  867. signUp(user: ParseUser, attrs: AttributeMap, options: RequestOptions): ParsePromise {
  868. var username = (attrs && attrs.username) || user.get('username');
  869. var password = (attrs && attrs.password) || user.get('password');
  870.  
  871. if (!username || !username.length) {
  872. return ParsePromise.error(
  873. new ParseError(
  874. ParseError.OTHER_CAUSE,
  875. 'Cannot sign up user with an empty name.'
  876. )
  877. );
  878. }
  879. if (!password || !password.length) {
  880. return ParsePromise.error(
  881. new ParseError(
  882. ParseError.OTHER_CAUSE,
  883. 'Cannot sign up user with an empty password.'
  884. )
  885. );
  886. }
  887.  
  888. return user.save(attrs, options).then(() => {
  889. // Clear the password field
  890. user._finishFetch({ password: undefined });
  891.  
  892. if (canUseCurrentUser) {
  893. return DefaultController.setCurrentUser(user);
  894. }
  895. return user;
  896. });
  897. },
  898.  
  899. logIn(user: ParseUser, options: RequestOptions): ParsePromise {
  900. var RESTController = CoreManager.getRESTController();
  901. var stateController = CoreManager.getObjectStateController();
  902. var auth = {
  903. username: user.get('username'),
  904. password: user.get('password')
  905. };
  906. return RESTController.request(
  907. 'GET', 'login', auth, options
  908. ).then((response, status) => {
  909. user._migrateId(response.objectId);
  910. user._setExisted(true);
  911. stateController.setPendingOp(
  912. user._getStateIdentifier(), 'username', undefined
  913. );
  914. stateController.setPendingOp(
  915. user._getStateIdentifier(), 'password', undefined
  916. );
  917. response.password = undefined;
  918. user._finishFetch(response);
  919. if (!canUseCurrentUser) {
  920. // We can't set the current user, so just return the one we logged in
  921. return ParsePromise.as(user);
  922. }
  923. return DefaultController.setCurrentUser(user);
  924. });
  925. },
  926.  
  927. become(options: RequestOptions): ParsePromise {
  928. var user = new ParseUser();
  929. var RESTController = CoreManager.getRESTController();
  930. return RESTController.request(
  931. 'GET', 'users/me', {}, options
  932. ).then((response, status) => {
  933. user._finishFetch(response);
  934. user._setExisted(true);
  935. return DefaultController.setCurrentUser(user);
  936. });
  937. },
  938.  
  939. logOut(): ParsePromise {
  940. return DefaultController.currentUserAsync().then((currentUser) => {
  941. var path = Storage.generatePath(CURRENT_USER_KEY);
  942. var promise = Storage.removeItemAsync(path);
  943. var RESTController = CoreManager.getRESTController();
  944. if (currentUser !== null) {
  945. var currentSession = currentUser.getSessionToken();
  946. if (currentSession && isRevocableSession(currentSession)) {
  947. promise = promise.then(() => {
  948. return RESTController.request(
  949. 'POST', 'logout', {}, { sessionToken: currentSession }
  950. );
  951. });
  952. }
  953. currentUser._logOutWithAll();
  954. currentUser._finishFetch({ sessionToken: undefined });
  955. }
  956. currentUserCacheMatchesDisk = true;
  957. currentUserCache = null;
  958.  
  959. return promise;
  960. });
  961. },
  962.  
  963. requestPasswordReset(email: string, options: RequestOptions) {
  964. var RESTController = CoreManager.getRESTController();
  965. return RESTController.request(
  966. 'POST',
  967. 'requestPasswordReset',
  968. { email: email },
  969. options
  970. );
  971. },
  972.  
  973. upgradeToRevocableSession(user: ParseUser, options: RequestOptions) {
  974. var token = user.getSessionToken();
  975. if (!token) {
  976. return ParsePromise.error(
  977. new ParseError(
  978. ParseError.SESSION_MISSING,
  979. 'Cannot upgrade a user with no session token'
  980. )
  981. );
  982. }
  983.  
  984. options.sessionToken = token;
  985.  
  986. var RESTController = CoreManager.getRESTController();
  987. return RESTController.request(
  988. 'POST',
  989. 'upgradeToRevocableSession',
  990. {},
  991. options
  992. ).then((result) => {
  993. var session = new ParseSession();
  994. session._finishFetch(result);
  995. user._finishFetch({ sessionToken: session.getSessionToken() });
  996. if (user.isCurrent()) {
  997. return DefaultController.setCurrentUser(user);
  998. }
  999. return ParsePromise.as(user);
  1000. });
  1001. },
  1002.  
  1003. linkWith(user: ParseUser, authData: AuthData) {
  1004. return user.save({ authData }).then(() => {
  1005. user.set("authData", authData);
  1006. if (canUseCurrentUser) {
  1007. return DefaultController.setCurrentUser(user);
  1008. }
  1009. return user;
  1010. });
  1011. }
  1012. };
  1013.  
  1014. CoreManager.setUserController(DefaultController);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement