ParseUser.js 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _CoreManager = _interopRequireDefault(require("./CoreManager"));
  7. var _isRevocableSession = _interopRequireDefault(require("./isRevocableSession"));
  8. var _ParseError = _interopRequireDefault(require("./ParseError"));
  9. var _ParseObject = _interopRequireDefault(require("./ParseObject"));
  10. var _ParseSession = _interopRequireDefault(require("./ParseSession"));
  11. var _Storage = _interopRequireDefault(require("./Storage"));
  12. function _interopRequireDefault(obj) {
  13. return obj && obj.__esModule ? obj : {
  14. default: obj
  15. };
  16. }
  17. /**
  18. * Copyright (c) 2015-present, Parse, LLC.
  19. * All rights reserved.
  20. *
  21. * This source code is licensed under the BSD-style license found in the
  22. * LICENSE file in the root directory of this source tree. An additional grant
  23. * of patent rights can be found in the PATENTS file in the same directory.
  24. *
  25. * @flow
  26. */
  27. const CURRENT_USER_KEY = 'currentUser';
  28. let canUseCurrentUser = !_CoreManager.default.get('IS_NODE');
  29. let currentUserCacheMatchesDisk = false;
  30. let currentUserCache = null;
  31. const authProviders = {};
  32. /**
  33. * <p>A Parse.User object is a local representation of a user persisted to the
  34. * Parse cloud. This class is a subclass of a Parse.Object, and retains the
  35. * same functionality of a Parse.Object, but also extends it with various
  36. * user specific methods, like authentication, signing up, and validation of
  37. * uniqueness.</p>
  38. *
  39. * @alias Parse.User
  40. * @augments Parse.Object
  41. */
  42. class ParseUser extends _ParseObject.default {
  43. /**
  44. * @param {object} attributes The initial set of data to store in the user.
  45. */
  46. constructor(attributes
  47. /*: ?AttributeMap*/
  48. ) {
  49. super('_User');
  50. if (attributes && typeof attributes === 'object') {
  51. if (!this.set(attributes || {})) {
  52. throw new Error("Can't create an invalid Parse User");
  53. }
  54. }
  55. }
  56. /**
  57. * Request a revocable session token to replace the older style of token.
  58. *
  59. * @param {object} options
  60. * @returns {Promise} A promise that is resolved when the replacement
  61. * token has been fetched.
  62. */
  63. _upgradeToRevocableSession(options
  64. /*: RequestOptions*/
  65. )
  66. /*: Promise<void>*/
  67. {
  68. options = options || {};
  69. const upgradeOptions = {};
  70. if (options.hasOwnProperty('useMasterKey')) {
  71. upgradeOptions.useMasterKey = options.useMasterKey;
  72. }
  73. const controller = _CoreManager.default.getUserController();
  74. return controller.upgradeToRevocableSession(this, upgradeOptions);
  75. }
  76. /**
  77. * Parse allows you to link your users with {@link https://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication 3rd party authentication}, enabling
  78. * your users to sign up or log into your application using their existing identities.
  79. * Since 2.9.0
  80. *
  81. * @see {@link https://docs.parseplatform.org/js/guide/#linking-users Linking Users}
  82. * @param {string | AuthProvider} provider Name of auth provider or {@link https://parseplatform.org/Parse-SDK-JS/api/master/AuthProvider.html AuthProvider}
  83. * @param {object} options
  84. * <ul>
  85. * <li>If provider is string, options is {@link http://docs.parseplatform.org/parse-server/guide/#supported-3rd-party-authentications authData}
  86. * <li>If provider is AuthProvider, options is saveOpts
  87. * </ul>
  88. * @param {object} saveOpts useMasterKey / sessionToken
  89. * @returns {Promise} A promise that is fulfilled with the user is linked
  90. */
  91. linkWith(provider
  92. /*: any*/
  93. , options
  94. /*: { authData?: AuthData }*/
  95. , saveOpts
  96. /*:: ?: FullOptions*/
  97. = {})
  98. /*: Promise<ParseUser>*/
  99. {
  100. saveOpts.sessionToken = saveOpts.sessionToken || this.getSessionToken() || '';
  101. let authType;
  102. if (typeof provider === 'string') {
  103. authType = provider;
  104. if (authProviders[provider]) {
  105. provider = authProviders[provider];
  106. } else {
  107. const authProvider = {
  108. restoreAuthentication() {
  109. return true;
  110. },
  111. getAuthType() {
  112. return authType;
  113. }
  114. };
  115. authProviders[authProvider.getAuthType()] = authProvider;
  116. provider = authProvider;
  117. }
  118. } else {
  119. authType = provider.getAuthType();
  120. }
  121. if (options && options.hasOwnProperty('authData')) {
  122. const authData = this.get('authData') || {};
  123. if (typeof authData !== 'object') {
  124. throw new Error('Invalid type: authData field should be an object');
  125. }
  126. authData[authType] = options.authData;
  127. const controller = _CoreManager.default.getUserController();
  128. return controller.linkWith(this, authData, saveOpts);
  129. } else {
  130. return new Promise((resolve, reject) => {
  131. provider.authenticate({
  132. success: (provider, result) => {
  133. const opts = {};
  134. opts.authData = result;
  135. this.linkWith(provider, opts, saveOpts).then(() => {
  136. resolve(this);
  137. }, error => {
  138. reject(error);
  139. });
  140. },
  141. error: (provider, error) => {
  142. reject(error);
  143. }
  144. });
  145. });
  146. }
  147. }
  148. /**
  149. * @param provider
  150. * @param options
  151. * @param saveOpts
  152. * @deprecated since 2.9.0 see {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.User.html#linkWith linkWith}
  153. * @returns {Promise}
  154. */
  155. _linkWith(provider
  156. /*: any*/
  157. , options
  158. /*: { authData?: AuthData }*/
  159. , saveOpts
  160. /*:: ?: FullOptions*/
  161. = {})
  162. /*: Promise<ParseUser>*/
  163. {
  164. return this.linkWith(provider, options, saveOpts);
  165. }
  166. /**
  167. * Synchronizes auth data for a provider (e.g. puts the access token in the
  168. * right place to be used by the Facebook SDK).
  169. *
  170. * @param provider
  171. */
  172. _synchronizeAuthData(provider
  173. /*: string*/
  174. ) {
  175. if (!this.isCurrent() || !provider) {
  176. return;
  177. }
  178. let authType;
  179. if (typeof provider === 'string') {
  180. authType = provider;
  181. provider = authProviders[authType];
  182. } else {
  183. authType = provider.getAuthType();
  184. }
  185. const authData = this.get('authData');
  186. if (!provider || !authData || typeof authData !== 'object') {
  187. return;
  188. }
  189. const success = provider.restoreAuthentication(authData[authType]);
  190. if (!success) {
  191. this._unlinkFrom(provider);
  192. }
  193. }
  194. /**
  195. * Synchronizes authData for all providers.
  196. */
  197. _synchronizeAllAuthData() {
  198. const authData = this.get('authData');
  199. if (typeof authData !== 'object') {
  200. return;
  201. }
  202. for (const key in authData) {
  203. this._synchronizeAuthData(key);
  204. }
  205. }
  206. /**
  207. * Removes null values from authData (which exist temporarily for unlinking)
  208. */
  209. _cleanupAuthData() {
  210. if (!this.isCurrent()) {
  211. return;
  212. }
  213. const authData = this.get('authData');
  214. if (typeof authData !== 'object') {
  215. return;
  216. }
  217. for (const key in authData) {
  218. if (!authData[key]) {
  219. delete authData[key];
  220. }
  221. }
  222. }
  223. /**
  224. * Unlinks a user from a service.
  225. *
  226. * @param {string | AuthProvider} provider Name of auth provider or {@link https://parseplatform.org/Parse-SDK-JS/api/master/AuthProvider.html AuthProvider}
  227. * @param {object} options MasterKey / SessionToken
  228. * @returns {Promise} A promise that is fulfilled when the unlinking
  229. * finishes.
  230. */
  231. _unlinkFrom(provider
  232. /*: any*/
  233. , options
  234. /*:: ?: FullOptions*/
  235. )
  236. /*: Promise<ParseUser>*/
  237. {
  238. return this.linkWith(provider, {
  239. authData: null
  240. }, options).then(() => {
  241. this._synchronizeAuthData(provider);
  242. return Promise.resolve(this);
  243. });
  244. }
  245. /**
  246. * Checks whether a user is linked to a service.
  247. *
  248. * @param {object} provider service to link to
  249. * @returns {boolean} true if link was successful
  250. */
  251. _isLinked(provider
  252. /*: any*/
  253. )
  254. /*: boolean*/
  255. {
  256. let authType;
  257. if (typeof provider === 'string') {
  258. authType = provider;
  259. } else {
  260. authType = provider.getAuthType();
  261. }
  262. const authData = this.get('authData') || {};
  263. if (typeof authData !== 'object') {
  264. return false;
  265. }
  266. return !!authData[authType];
  267. }
  268. /**
  269. * Deauthenticates all providers.
  270. */
  271. _logOutWithAll() {
  272. const authData = this.get('authData');
  273. if (typeof authData !== 'object') {
  274. return;
  275. }
  276. for (const key in authData) {
  277. this._logOutWith(key);
  278. }
  279. }
  280. /**
  281. * Deauthenticates a single provider (e.g. removing access tokens from the
  282. * Facebook SDK).
  283. *
  284. * @param {object} provider service to logout of
  285. */
  286. _logOutWith(provider
  287. /*: any*/
  288. ) {
  289. if (!this.isCurrent()) {
  290. return;
  291. }
  292. if (typeof provider === 'string') {
  293. provider = authProviders[provider];
  294. }
  295. if (provider && provider.deauthenticate) {
  296. provider.deauthenticate();
  297. }
  298. }
  299. /**
  300. * Class instance method used to maintain specific keys when a fetch occurs.
  301. * Used to ensure that the session token is not lost.
  302. *
  303. * @returns {object} sessionToken
  304. */
  305. _preserveFieldsOnFetch()
  306. /*: AttributeMap*/
  307. {
  308. return {
  309. sessionToken: this.get('sessionToken')
  310. };
  311. }
  312. /**
  313. * Returns true if <code>current</code> would return this user.
  314. *
  315. * @returns {boolean} true if user is cached on disk
  316. */
  317. isCurrent()
  318. /*: boolean*/
  319. {
  320. const current = ParseUser.current();
  321. return !!current && current.id === this.id;
  322. }
  323. /**
  324. * Returns true if <code>current</code> would return this user.
  325. *
  326. * @returns {Promise<boolean>} true if user is cached on disk
  327. */
  328. async isCurrentAsync()
  329. /*: Promise<boolean>*/
  330. {
  331. const current = await ParseUser.currentAsync();
  332. return !!current && current.id === this.id;
  333. }
  334. /**
  335. * Returns get("username").
  336. *
  337. * @returns {string}
  338. */
  339. getUsername()
  340. /*: ?string*/
  341. {
  342. const username = this.get('username');
  343. if (username == null || typeof username === 'string') {
  344. return username;
  345. }
  346. return '';
  347. }
  348. /**
  349. * Calls set("username", username, options) and returns the result.
  350. *
  351. * @param {string} username
  352. */
  353. setUsername(username
  354. /*: string*/
  355. ) {
  356. // Strip anonymity
  357. const authData = this.get('authData');
  358. if (authData && typeof authData === 'object' && authData.hasOwnProperty('anonymous')) {
  359. // We need to set anonymous to null instead of deleting it in order to remove it from Parse.
  360. authData.anonymous = null;
  361. }
  362. this.set('username', username);
  363. }
  364. /**
  365. * Calls set("password", password, options) and returns the result.
  366. *
  367. * @param {string} password User's Password
  368. */
  369. setPassword(password
  370. /*: string*/
  371. ) {
  372. this.set('password', password);
  373. }
  374. /**
  375. * Returns get("email").
  376. *
  377. * @returns {string} User's Email
  378. */
  379. getEmail()
  380. /*: ?string*/
  381. {
  382. const email = this.get('email');
  383. if (email == null || typeof email === 'string') {
  384. return email;
  385. }
  386. return '';
  387. }
  388. /**
  389. * Calls set("email", email) and returns the result.
  390. *
  391. * @param {string} email
  392. * @returns {boolean}
  393. */
  394. setEmail(email
  395. /*: string*/
  396. ) {
  397. return this.set('email', email);
  398. }
  399. /**
  400. * Returns the session token for this user, if the user has been logged in,
  401. * or if it is the result of a query with the master key. Otherwise, returns
  402. * undefined.
  403. *
  404. * @returns {string} the session token, or undefined
  405. */
  406. getSessionToken()
  407. /*: ?string*/
  408. {
  409. const token = this.get('sessionToken');
  410. if (token == null || typeof token === 'string') {
  411. return token;
  412. }
  413. return '';
  414. }
  415. /**
  416. * Checks whether this user is the current user and has been authenticated.
  417. *
  418. * @returns {boolean} whether this user is the current user and is logged in.
  419. */
  420. authenticated()
  421. /*: boolean*/
  422. {
  423. const current = ParseUser.current();
  424. return !!this.get('sessionToken') && !!current && current.id === this.id;
  425. }
  426. /**
  427. * Signs up a new user. You should call this instead of save for
  428. * new Parse.Users. This will create a new Parse.User on the server, and
  429. * also persist the session on disk so that you can access the user using
  430. * <code>current</code>.
  431. *
  432. * <p>A username and password must be set before calling signUp.</p>
  433. *
  434. * @param {object} attrs Extra fields to set on the new user, or null.
  435. * @param {object} options
  436. * @returns {Promise} A promise that is fulfilled when the signup
  437. * finishes.
  438. */
  439. signUp(attrs
  440. /*: AttributeMap*/
  441. , options
  442. /*:: ?: FullOptions*/
  443. )
  444. /*: Promise<ParseUser>*/
  445. {
  446. options = options || {};
  447. const signupOptions = {};
  448. if (options.hasOwnProperty('useMasterKey')) {
  449. signupOptions.useMasterKey = options.useMasterKey;
  450. }
  451. if (options.hasOwnProperty('installationId')) {
  452. signupOptions.installationId = options.installationId;
  453. }
  454. if (options.hasOwnProperty('context') && Object.prototype.toString.call(options.context) === '[object Object]') {
  455. signupOptions.context = options.context;
  456. }
  457. const controller = _CoreManager.default.getUserController();
  458. return controller.signUp(this, attrs, signupOptions);
  459. }
  460. /**
  461. * Logs in a Parse.User. On success, this saves the session to disk,
  462. * so you can retrieve the currently logged in user using
  463. * <code>current</code>.
  464. *
  465. * <p>A username and password must be set before calling logIn.</p>
  466. *
  467. * @param {object} options
  468. * @returns {Promise} A promise that is fulfilled with the user when
  469. * the login is complete.
  470. */
  471. logIn(options
  472. /*:: ?: FullOptions*/
  473. )
  474. /*: Promise<ParseUser>*/
  475. {
  476. options = options || {};
  477. const loginOptions = {
  478. usePost: true
  479. };
  480. if (options.hasOwnProperty('useMasterKey')) {
  481. loginOptions.useMasterKey = options.useMasterKey;
  482. }
  483. if (options.hasOwnProperty('installationId')) {
  484. loginOptions.installationId = options.installationId;
  485. }
  486. if (options.hasOwnProperty('usePost')) {
  487. loginOptions.usePost = options.usePost;
  488. }
  489. const controller = _CoreManager.default.getUserController();
  490. return controller.logIn(this, loginOptions);
  491. }
  492. /**
  493. * Wrap the default save behavior with functionality to save to local
  494. * storage if this is current user.
  495. *
  496. * @param {...any} args
  497. * @returns {Promise}
  498. */
  499. async save(...args)
  500. /*: Promise<ParseUser>*/
  501. {
  502. await super.save.apply(this, args);
  503. const current = await this.isCurrentAsync();
  504. if (current) {
  505. return _CoreManager.default.getUserController().updateUserOnDisk(this);
  506. }
  507. return this;
  508. }
  509. /**
  510. * Wrap the default destroy behavior with functionality that logs out
  511. * the current user when it is destroyed
  512. *
  513. * @param {...any} args
  514. * @returns {Parse.User}
  515. */
  516. async destroy(...args)
  517. /*: Promise<ParseUser>*/
  518. {
  519. await super.destroy.apply(this, args);
  520. const current = await this.isCurrentAsync();
  521. if (current) {
  522. return _CoreManager.default.getUserController().removeUserFromDisk();
  523. }
  524. return this;
  525. }
  526. /**
  527. * Wrap the default fetch behavior with functionality to save to local
  528. * storage if this is current user.
  529. *
  530. * @param {...any} args
  531. * @returns {Parse.User}
  532. */
  533. async fetch(...args)
  534. /*: Promise<ParseUser>*/
  535. {
  536. await super.fetch.apply(this, args);
  537. const current = await this.isCurrentAsync();
  538. if (current) {
  539. return _CoreManager.default.getUserController().updateUserOnDisk(this);
  540. }
  541. return this;
  542. }
  543. /**
  544. * Wrap the default fetchWithInclude behavior with functionality to save to local
  545. * storage if this is current user.
  546. *
  547. * @param {...any} args
  548. * @returns {Parse.User}
  549. */
  550. async fetchWithInclude(...args)
  551. /*: Promise<ParseUser>*/
  552. {
  553. await super.fetchWithInclude.apply(this, args);
  554. const current = await this.isCurrentAsync();
  555. if (current) {
  556. return _CoreManager.default.getUserController().updateUserOnDisk(this);
  557. }
  558. return this;
  559. }
  560. /**
  561. * Verify whether a given password is the password of the current user.
  562. *
  563. * @param {string} password A password to be verified
  564. * @param {object} options
  565. * @returns {Promise} A promise that is fulfilled with a user
  566. * when the password is correct.
  567. */
  568. verifyPassword(password
  569. /*: string*/
  570. , options
  571. /*:: ?: RequestOptions*/
  572. )
  573. /*: Promise<ParseUser>*/
  574. {
  575. const username = this.getUsername() || '';
  576. return ParseUser.verifyPassword(username, password, options);
  577. }
  578. static readOnlyAttributes() {
  579. return ['sessionToken'];
  580. }
  581. /**
  582. * Adds functionality to the existing Parse.User class.
  583. *
  584. * @param {object} protoProps A set of properties to add to the prototype
  585. * @param {object} classProps A set of static properties to add to the class
  586. * @static
  587. * @returns {Parse.User} The newly extended Parse.User class
  588. */
  589. static extend(protoProps
  590. /*: { [prop: string]: any }*/
  591. , classProps
  592. /*: { [prop: string]: any }*/
  593. ) {
  594. if (protoProps) {
  595. for (const prop in protoProps) {
  596. if (prop !== 'className') {
  597. Object.defineProperty(ParseUser.prototype, prop, {
  598. value: protoProps[prop],
  599. enumerable: false,
  600. writable: true,
  601. configurable: true
  602. });
  603. }
  604. }
  605. }
  606. if (classProps) {
  607. for (const prop in classProps) {
  608. if (prop !== 'className') {
  609. Object.defineProperty(ParseUser, prop, {
  610. value: classProps[prop],
  611. enumerable: false,
  612. writable: true,
  613. configurable: true
  614. });
  615. }
  616. }
  617. }
  618. return ParseUser;
  619. }
  620. /**
  621. * Retrieves the currently logged in ParseUser with a valid session,
  622. * either from memory or localStorage, if necessary.
  623. *
  624. * @static
  625. * @returns {Parse.Object} The currently logged in Parse.User.
  626. */
  627. static current()
  628. /*: ?ParseUser*/
  629. {
  630. if (!canUseCurrentUser) {
  631. return null;
  632. }
  633. const controller = _CoreManager.default.getUserController();
  634. return controller.currentUser();
  635. }
  636. /**
  637. * Retrieves the currently logged in ParseUser from asynchronous Storage.
  638. *
  639. * @static
  640. * @returns {Promise} A Promise that is resolved with the currently
  641. * logged in Parse User
  642. */
  643. static currentAsync()
  644. /*: Promise<?ParseUser>*/
  645. {
  646. if (!canUseCurrentUser) {
  647. return Promise.resolve(null);
  648. }
  649. const controller = _CoreManager.default.getUserController();
  650. return controller.currentUserAsync();
  651. }
  652. /**
  653. * Signs up a new user with a username (or email) and password.
  654. * This will create a new Parse.User on the server, and also persist the
  655. * session in localStorage so that you can access the user using
  656. * {@link #current}.
  657. *
  658. * @param {string} username The username (or email) to sign up with.
  659. * @param {string} password The password to sign up with.
  660. * @param {object} attrs Extra fields to set on the new user.
  661. * @param {object} options
  662. * @static
  663. * @returns {Promise} A promise that is fulfilled with the user when
  664. * the signup completes.
  665. */
  666. static signUp(username
  667. /*: string*/
  668. , password
  669. /*: string*/
  670. , attrs
  671. /*: AttributeMap*/
  672. , options
  673. /*:: ?: FullOptions*/
  674. ) {
  675. attrs = attrs || {};
  676. attrs.username = username;
  677. attrs.password = password;
  678. const user = new this(attrs);
  679. return user.signUp({}, options);
  680. }
  681. /**
  682. * Logs in a user with a username (or email) and password. On success, this
  683. * saves the session to disk, so you can retrieve the currently logged in
  684. * user using <code>current</code>.
  685. *
  686. * @param {string} username The username (or email) to log in with.
  687. * @param {string} password The password to log in with.
  688. * @param {object} options
  689. * @static
  690. * @returns {Promise} A promise that is fulfilled with the user when
  691. * the login completes.
  692. */
  693. static logIn(username
  694. /*: string*/
  695. , password
  696. /*: string*/
  697. , options
  698. /*:: ?: FullOptions*/
  699. ) {
  700. if (typeof username !== 'string') {
  701. return Promise.reject(new _ParseError.default(_ParseError.default.OTHER_CAUSE, 'Username must be a string.'));
  702. } else if (typeof password !== 'string') {
  703. return Promise.reject(new _ParseError.default(_ParseError.default.OTHER_CAUSE, 'Password must be a string.'));
  704. }
  705. const user = new this();
  706. user._finishFetch({
  707. username: username,
  708. password: password
  709. });
  710. return user.logIn(options);
  711. }
  712. /**
  713. * Logs in a user with a session token. On success, this saves the session
  714. * to disk, so you can retrieve the currently logged in user using
  715. * <code>current</code>.
  716. *
  717. * @param {string} sessionToken The sessionToken to log in with.
  718. * @param {object} options
  719. * @static
  720. * @returns {Promise} A promise that is fulfilled with the user when
  721. * the login completes.
  722. */
  723. static become(sessionToken
  724. /*: string*/
  725. , options
  726. /*:: ?: RequestOptions*/
  727. ) {
  728. if (!canUseCurrentUser) {
  729. throw new Error('It is not memory-safe to become a user in a server environment');
  730. }
  731. options = options || {};
  732. const becomeOptions
  733. /*: RequestOptions*/
  734. = {
  735. sessionToken: sessionToken
  736. };
  737. if (options.hasOwnProperty('useMasterKey')) {
  738. becomeOptions.useMasterKey = options.useMasterKey;
  739. }
  740. const controller = _CoreManager.default.getUserController();
  741. const user = new this();
  742. return controller.become(user, becomeOptions);
  743. }
  744. /**
  745. * Retrieves a user with a session token.
  746. *
  747. * @param {string} sessionToken The sessionToken to get user with.
  748. * @param {object} options
  749. * @static
  750. * @returns {Promise} A promise that is fulfilled with the user is fetched.
  751. */
  752. static me(sessionToken
  753. /*: string*/
  754. , options
  755. /*:: ?: RequestOptions*/
  756. = {}) {
  757. const controller = _CoreManager.default.getUserController();
  758. const meOptions
  759. /*: RequestOptions*/
  760. = {
  761. sessionToken: sessionToken
  762. };
  763. if (options.useMasterKey) {
  764. meOptions.useMasterKey = options.useMasterKey;
  765. }
  766. const user = new this();
  767. return controller.me(user, meOptions);
  768. }
  769. /**
  770. * Logs in a user with a session token. On success, this saves the session
  771. * to disk, so you can retrieve the currently logged in user using
  772. * <code>current</code>. If there is no session token the user will not logged in.
  773. *
  774. * @param {object} userJSON The JSON map of the User's data
  775. * @static
  776. * @returns {Promise} A promise that is fulfilled with the user when
  777. * the login completes.
  778. */
  779. static hydrate(userJSON
  780. /*: AttributeMap*/
  781. ) {
  782. const controller = _CoreManager.default.getUserController();
  783. const user = new this();
  784. return controller.hydrate(user, userJSON);
  785. }
  786. /**
  787. * Static version of {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.User.html#linkWith linkWith}
  788. *
  789. * @param provider
  790. * @param options
  791. * @param saveOpts
  792. * @static
  793. * @returns {Promise}
  794. */
  795. static logInWith(provider
  796. /*: any*/
  797. , options
  798. /*: { authData?: AuthData }*/
  799. , saveOpts
  800. /*:: ?: FullOptions*/
  801. )
  802. /*: Promise<ParseUser>*/
  803. {
  804. const user = new this();
  805. return user.linkWith(provider, options, saveOpts);
  806. }
  807. /**
  808. * Logs out the currently logged in user session. This will remove the
  809. * session from disk, log out of linked services, and future calls to
  810. * <code>current</code> will return <code>null</code>.
  811. *
  812. * @param {object} options
  813. * @static
  814. * @returns {Promise} A promise that is resolved when the session is
  815. * destroyed on the server.
  816. */
  817. static logOut(options
  818. /*: RequestOptions*/
  819. = {}) {
  820. const controller = _CoreManager.default.getUserController();
  821. return controller.logOut(options);
  822. }
  823. /**
  824. * Requests a password reset email to be sent to the specified email address
  825. * associated with the user account. This email allows the user to securely
  826. * reset their password on the Parse site.
  827. *
  828. * @param {string} email The email address associated with the user that
  829. * forgot their password.
  830. * @param {object} options
  831. * @static
  832. * @returns {Promise}
  833. */
  834. static requestPasswordReset(email
  835. /*: string*/
  836. , options
  837. /*:: ?: RequestOptions*/
  838. ) {
  839. options = options || {};
  840. const requestOptions = {};
  841. if (options.hasOwnProperty('useMasterKey')) {
  842. requestOptions.useMasterKey = options.useMasterKey;
  843. }
  844. const controller = _CoreManager.default.getUserController();
  845. return controller.requestPasswordReset(email, requestOptions);
  846. }
  847. /**
  848. * Request an email verification.
  849. *
  850. * @param {string} email The email address associated with the user that
  851. * needs to verify their email.
  852. * @param {object} options
  853. * @static
  854. * @returns {Promise}
  855. */
  856. static requestEmailVerification(email
  857. /*: string*/
  858. , options
  859. /*:: ?: RequestOptions*/
  860. ) {
  861. options = options || {};
  862. const requestOptions = {};
  863. if (options.hasOwnProperty('useMasterKey')) {
  864. requestOptions.useMasterKey = options.useMasterKey;
  865. }
  866. const controller = _CoreManager.default.getUserController();
  867. return controller.requestEmailVerification(email, requestOptions);
  868. }
  869. /**
  870. * Verify whether a given password is the password of the current user.
  871. *
  872. * @param {string} username A username to be used for identificaiton
  873. * @param {string} password A password to be verified
  874. * @param {object} options
  875. * @static
  876. * @returns {Promise} A promise that is fulfilled with a user
  877. * when the password is correct.
  878. */
  879. static verifyPassword(username
  880. /*: string*/
  881. , password
  882. /*: string*/
  883. , options
  884. /*:: ?: RequestOptions*/
  885. ) {
  886. if (typeof username !== 'string') {
  887. return Promise.reject(new _ParseError.default(_ParseError.default.OTHER_CAUSE, 'Username must be a string.'));
  888. }
  889. if (typeof password !== 'string') {
  890. return Promise.reject(new _ParseError.default(_ParseError.default.OTHER_CAUSE, 'Password must be a string.'));
  891. }
  892. options = options || {};
  893. const verificationOption = {};
  894. if (options.hasOwnProperty('useMasterKey')) {
  895. verificationOption.useMasterKey = options.useMasterKey;
  896. }
  897. const controller = _CoreManager.default.getUserController();
  898. return controller.verifyPassword(username, password, verificationOption);
  899. }
  900. /**
  901. * Allow someone to define a custom User class without className
  902. * being rewritten to _User. The default behavior is to rewrite
  903. * User to _User for legacy reasons. This allows developers to
  904. * override that behavior.
  905. *
  906. * @param {boolean} isAllowed Whether or not to allow custom User class
  907. * @static
  908. */
  909. static allowCustomUserClass(isAllowed
  910. /*: boolean*/
  911. ) {
  912. _CoreManager.default.set('PERFORM_USER_REWRITE', !isAllowed);
  913. }
  914. /**
  915. * Allows a legacy application to start using revocable sessions. If the
  916. * current session token is not revocable, a request will be made for a new,
  917. * revocable session.
  918. * It is not necessary to call this method from cloud code unless you are
  919. * handling user signup or login from the server side. In a cloud code call,
  920. * this function will not attempt to upgrade the current token.
  921. *
  922. * @param {object} options
  923. * @static
  924. * @returns {Promise} A promise that is resolved when the process has
  925. * completed. If a replacement session token is requested, the promise
  926. * will be resolved after a new token has been fetched.
  927. */
  928. static enableRevocableSession(options
  929. /*:: ?: RequestOptions*/
  930. ) {
  931. options = options || {};
  932. _CoreManager.default.set('FORCE_REVOCABLE_SESSION', true);
  933. if (canUseCurrentUser) {
  934. const current = ParseUser.current();
  935. if (current) {
  936. return current._upgradeToRevocableSession(options);
  937. }
  938. }
  939. return Promise.resolve();
  940. }
  941. /**
  942. * Enables the use of become or the current user in a server
  943. * environment. These features are disabled by default, since they depend on
  944. * global objects that are not memory-safe for most servers.
  945. *
  946. * @static
  947. */
  948. static enableUnsafeCurrentUser() {
  949. canUseCurrentUser = true;
  950. }
  951. /**
  952. * Disables the use of become or the current user in any environment.
  953. * These features are disabled on servers by default, since they depend on
  954. * global objects that are not memory-safe for most servers.
  955. *
  956. * @static
  957. */
  958. static disableUnsafeCurrentUser() {
  959. canUseCurrentUser = false;
  960. }
  961. /**
  962. * When registering users with {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.User.html#linkWith linkWith} a basic auth provider
  963. * is automatically created for you.
  964. *
  965. * For advanced authentication, you can register an Auth provider to
  966. * implement custom authentication, deauthentication.
  967. *
  968. * @param provider
  969. * @see {@link https://parseplatform.org/Parse-SDK-JS/api/master/AuthProvider.html AuthProvider}
  970. * @see {@link https://docs.parseplatform.org/js/guide/#custom-authentication-module Custom Authentication Module}
  971. * @static
  972. */
  973. static _registerAuthenticationProvider(provider
  974. /*: any*/
  975. ) {
  976. authProviders[provider.getAuthType()] = provider; // Synchronize the current user with the auth provider.
  977. ParseUser.currentAsync().then(current => {
  978. if (current) {
  979. current._synchronizeAuthData(provider.getAuthType());
  980. }
  981. });
  982. }
  983. /**
  984. * @param provider
  985. * @param options
  986. * @param saveOpts
  987. * @deprecated since 2.9.0 see {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.User.html#logInWith logInWith}
  988. * @static
  989. * @returns {Promise}
  990. */
  991. static _logInWith(provider
  992. /*: any*/
  993. , options
  994. /*: { authData?: AuthData }*/
  995. , saveOpts
  996. /*:: ?: FullOptions*/
  997. ) {
  998. const user = new this();
  999. return user.linkWith(provider, options, saveOpts);
  1000. }
  1001. static _clearCache() {
  1002. currentUserCache = null;
  1003. currentUserCacheMatchesDisk = false;
  1004. }
  1005. static _setCurrentUserCache(user
  1006. /*: ParseUser*/
  1007. ) {
  1008. currentUserCache = user;
  1009. }
  1010. }
  1011. _ParseObject.default.registerSubclass('_User', ParseUser);
  1012. const DefaultController = {
  1013. updateUserOnDisk(user) {
  1014. const path = _Storage.default.generatePath(CURRENT_USER_KEY);
  1015. const json = user.toJSON();
  1016. delete json.password;
  1017. json.className = '_User';
  1018. let userData = JSON.stringify(json);
  1019. if (_CoreManager.default.get('ENCRYPTED_USER')) {
  1020. const crypto = _CoreManager.default.getCryptoController();
  1021. userData = crypto.encrypt(json, _CoreManager.default.get('ENCRYPTED_KEY'));
  1022. }
  1023. return _Storage.default.setItemAsync(path, userData).then(() => {
  1024. return user;
  1025. });
  1026. },
  1027. removeUserFromDisk() {
  1028. const path = _Storage.default.generatePath(CURRENT_USER_KEY);
  1029. currentUserCacheMatchesDisk = true;
  1030. currentUserCache = null;
  1031. return _Storage.default.removeItemAsync(path);
  1032. },
  1033. setCurrentUser(user) {
  1034. currentUserCache = user;
  1035. user._cleanupAuthData();
  1036. user._synchronizeAllAuthData();
  1037. return DefaultController.updateUserOnDisk(user);
  1038. },
  1039. currentUser()
  1040. /*: ?ParseUser*/
  1041. {
  1042. if (currentUserCache) {
  1043. return currentUserCache;
  1044. }
  1045. if (currentUserCacheMatchesDisk) {
  1046. return null;
  1047. }
  1048. if (_Storage.default.async()) {
  1049. throw new Error('Cannot call currentUser() when using a platform with an async ' + 'storage system. Call currentUserAsync() instead.');
  1050. }
  1051. const path = _Storage.default.generatePath(CURRENT_USER_KEY);
  1052. let userData = _Storage.default.getItem(path);
  1053. currentUserCacheMatchesDisk = true;
  1054. if (!userData) {
  1055. currentUserCache = null;
  1056. return null;
  1057. }
  1058. if (_CoreManager.default.get('ENCRYPTED_USER')) {
  1059. const crypto = _CoreManager.default.getCryptoController();
  1060. userData = crypto.decrypt(userData, _CoreManager.default.get('ENCRYPTED_KEY'));
  1061. }
  1062. userData = JSON.parse(userData);
  1063. if (!userData.className) {
  1064. userData.className = '_User';
  1065. }
  1066. if (userData._id) {
  1067. if (userData.objectId !== userData._id) {
  1068. userData.objectId = userData._id;
  1069. }
  1070. delete userData._id;
  1071. }
  1072. if (userData._sessionToken) {
  1073. userData.sessionToken = userData._sessionToken;
  1074. delete userData._sessionToken;
  1075. }
  1076. const current = _ParseObject.default.fromJSON(userData);
  1077. currentUserCache = current;
  1078. current._synchronizeAllAuthData();
  1079. return current;
  1080. },
  1081. currentUserAsync()
  1082. /*: Promise<?ParseUser>*/
  1083. {
  1084. if (currentUserCache) {
  1085. return Promise.resolve(currentUserCache);
  1086. }
  1087. if (currentUserCacheMatchesDisk) {
  1088. return Promise.resolve(null);
  1089. }
  1090. const path = _Storage.default.generatePath(CURRENT_USER_KEY);
  1091. return _Storage.default.getItemAsync(path).then(userData => {
  1092. currentUserCacheMatchesDisk = true;
  1093. if (!userData) {
  1094. currentUserCache = null;
  1095. return Promise.resolve(null);
  1096. }
  1097. if (_CoreManager.default.get('ENCRYPTED_USER')) {
  1098. const crypto = _CoreManager.default.getCryptoController();
  1099. userData = crypto.decrypt(userData.toString(), _CoreManager.default.get('ENCRYPTED_KEY'));
  1100. }
  1101. userData = JSON.parse(userData);
  1102. if (!userData.className) {
  1103. userData.className = '_User';
  1104. }
  1105. if (userData._id) {
  1106. if (userData.objectId !== userData._id) {
  1107. userData.objectId = userData._id;
  1108. }
  1109. delete userData._id;
  1110. }
  1111. if (userData._sessionToken) {
  1112. userData.sessionToken = userData._sessionToken;
  1113. delete userData._sessionToken;
  1114. }
  1115. const current = _ParseObject.default.fromJSON(userData);
  1116. currentUserCache = current;
  1117. current._synchronizeAllAuthData();
  1118. return Promise.resolve(current);
  1119. });
  1120. },
  1121. signUp(user
  1122. /*: ParseUser*/
  1123. , attrs
  1124. /*: AttributeMap*/
  1125. , options
  1126. /*: RequestOptions*/
  1127. )
  1128. /*: Promise<ParseUser>*/
  1129. {
  1130. const username = attrs && attrs.username || user.get('username');
  1131. const password = attrs && attrs.password || user.get('password');
  1132. if (!username || !username.length) {
  1133. return Promise.reject(new _ParseError.default(_ParseError.default.OTHER_CAUSE, 'Cannot sign up user with an empty username.'));
  1134. }
  1135. if (!password || !password.length) {
  1136. return Promise.reject(new _ParseError.default(_ParseError.default.OTHER_CAUSE, 'Cannot sign up user with an empty password.'));
  1137. }
  1138. return user.save(attrs, options).then(() => {
  1139. // Clear the password field
  1140. user._finishFetch({
  1141. password: undefined
  1142. });
  1143. if (canUseCurrentUser) {
  1144. return DefaultController.setCurrentUser(user);
  1145. }
  1146. return user;
  1147. });
  1148. },
  1149. logIn(user
  1150. /*: ParseUser*/
  1151. , options
  1152. /*: RequestOptions*/
  1153. )
  1154. /*: Promise<ParseUser>*/
  1155. {
  1156. const RESTController = _CoreManager.default.getRESTController();
  1157. const stateController = _CoreManager.default.getObjectStateController();
  1158. const auth = {
  1159. username: user.get('username'),
  1160. password: user.get('password')
  1161. };
  1162. return RESTController.request(options.usePost ? 'POST' : 'GET', 'login', auth, options).then(response => {
  1163. user._migrateId(response.objectId);
  1164. user._setExisted(true);
  1165. stateController.setPendingOp(user._getStateIdentifier(), 'username', undefined);
  1166. stateController.setPendingOp(user._getStateIdentifier(), 'password', undefined);
  1167. response.password = undefined;
  1168. user._finishFetch(response);
  1169. if (!canUseCurrentUser) {
  1170. // We can't set the current user, so just return the one we logged in
  1171. return Promise.resolve(user);
  1172. }
  1173. return DefaultController.setCurrentUser(user);
  1174. });
  1175. },
  1176. become(user
  1177. /*: ParseUser*/
  1178. , options
  1179. /*: RequestOptions*/
  1180. )
  1181. /*: Promise<ParseUser>*/
  1182. {
  1183. const RESTController = _CoreManager.default.getRESTController();
  1184. return RESTController.request('GET', 'users/me', {}, options).then(response => {
  1185. user._finishFetch(response);
  1186. user._setExisted(true);
  1187. return DefaultController.setCurrentUser(user);
  1188. });
  1189. },
  1190. hydrate(user
  1191. /*: ParseUser*/
  1192. , userJSON
  1193. /*: AttributeMap*/
  1194. )
  1195. /*: Promise<ParseUser>*/
  1196. {
  1197. user._finishFetch(userJSON);
  1198. user._setExisted(true);
  1199. if (userJSON.sessionToken && canUseCurrentUser) {
  1200. return DefaultController.setCurrentUser(user);
  1201. } else {
  1202. return Promise.resolve(user);
  1203. }
  1204. },
  1205. me(user
  1206. /*: ParseUser*/
  1207. , options
  1208. /*: RequestOptions*/
  1209. )
  1210. /*: Promise<ParseUser>*/
  1211. {
  1212. const RESTController = _CoreManager.default.getRESTController();
  1213. return RESTController.request('GET', 'users/me', {}, options).then(response => {
  1214. user._finishFetch(response);
  1215. user._setExisted(true);
  1216. return user;
  1217. });
  1218. },
  1219. logOut(options
  1220. /*: RequestOptions*/
  1221. )
  1222. /*: Promise<ParseUser>*/
  1223. {
  1224. const RESTController = _CoreManager.default.getRESTController();
  1225. if (options.sessionToken) {
  1226. return RESTController.request('POST', 'logout', {}, options);
  1227. }
  1228. return DefaultController.currentUserAsync().then(currentUser => {
  1229. const path = _Storage.default.generatePath(CURRENT_USER_KEY);
  1230. let promise = _Storage.default.removeItemAsync(path);
  1231. if (currentUser !== null) {
  1232. const currentSession = currentUser.getSessionToken();
  1233. if (currentSession && (0, _isRevocableSession.default)(currentSession)) {
  1234. promise = promise.then(() => {
  1235. return RESTController.request('POST', 'logout', {}, {
  1236. sessionToken: currentSession
  1237. });
  1238. });
  1239. }
  1240. currentUser._logOutWithAll();
  1241. currentUser._finishFetch({
  1242. sessionToken: undefined
  1243. });
  1244. }
  1245. currentUserCacheMatchesDisk = true;
  1246. currentUserCache = null;
  1247. return promise;
  1248. });
  1249. },
  1250. requestPasswordReset(email
  1251. /*: string*/
  1252. , options
  1253. /*: RequestOptions*/
  1254. ) {
  1255. const RESTController = _CoreManager.default.getRESTController();
  1256. return RESTController.request('POST', 'requestPasswordReset', {
  1257. email: email
  1258. }, options);
  1259. },
  1260. async upgradeToRevocableSession(user
  1261. /*: ParseUser*/
  1262. , options
  1263. /*: RequestOptions*/
  1264. ) {
  1265. const token = user.getSessionToken();
  1266. if (!token) {
  1267. return Promise.reject(new _ParseError.default(_ParseError.default.SESSION_MISSING, 'Cannot upgrade a user with no session token'));
  1268. }
  1269. options.sessionToken = token;
  1270. const RESTController = _CoreManager.default.getRESTController();
  1271. const result = await RESTController.request('POST', 'upgradeToRevocableSession', {}, options);
  1272. const session = new _ParseSession.default();
  1273. session._finishFetch(result);
  1274. user._finishFetch({
  1275. sessionToken: session.getSessionToken()
  1276. });
  1277. const current = await user.isCurrentAsync();
  1278. if (current) {
  1279. return DefaultController.setCurrentUser(user);
  1280. }
  1281. return Promise.resolve(user);
  1282. },
  1283. linkWith(user
  1284. /*: ParseUser*/
  1285. , authData
  1286. /*: AuthData*/
  1287. , options
  1288. /*: FullOptions*/
  1289. ) {
  1290. return user.save({
  1291. authData
  1292. }, options).then(() => {
  1293. if (canUseCurrentUser) {
  1294. return DefaultController.setCurrentUser(user);
  1295. }
  1296. return user;
  1297. });
  1298. },
  1299. verifyPassword(username
  1300. /*: string*/
  1301. , password
  1302. /*: string*/
  1303. , options
  1304. /*: RequestOptions*/
  1305. ) {
  1306. const RESTController = _CoreManager.default.getRESTController();
  1307. return RESTController.request('GET', 'verifyPassword', {
  1308. username,
  1309. password
  1310. }, options);
  1311. },
  1312. requestEmailVerification(email
  1313. /*: string*/
  1314. , options
  1315. /*: RequestOptions*/
  1316. ) {
  1317. const RESTController = _CoreManager.default.getRESTController();
  1318. return RESTController.request('POST', 'verificationEmailRequest', {
  1319. email: email
  1320. }, options);
  1321. }
  1322. };
  1323. _CoreManager.default.setUserController(DefaultController);
  1324. var _default = ParseUser;
  1325. exports.default = _default;