UserEmailsTests.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. /* eslint-disable
  2. handle-callback-err,
  3. max-len,
  4. no-unused-vars,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * DS102: Remove unnecessary code created because of implicit returns
  11. * DS207: Consider shorter variations of null checks
  12. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  13. */
  14. const { expect } = require('chai')
  15. const async = require('async')
  16. const User = require('./helpers/User')
  17. const request = require('./helpers/request')
  18. const settings = require('settings-sharelatex')
  19. const { db, ObjectId } = require('../../../app/src/infrastructure/mongojs')
  20. const MockV1Api = require('./helpers/MockV1Api')
  21. describe('UserEmails', function() {
  22. beforeEach(function(done) {
  23. this.timeout(20000)
  24. this.user = new User()
  25. return this.user.login(done)
  26. })
  27. describe('confirming an email', function() {
  28. it('should confirm the email', function(done) {
  29. let token = null
  30. return async.series(
  31. [
  32. cb => {
  33. return this.user.request(
  34. {
  35. method: 'POST',
  36. url: '/user/emails',
  37. json: {
  38. email: 'newly-added-email@example.com'
  39. }
  40. },
  41. (error, response, body) => {
  42. if (error != null) {
  43. return done(error)
  44. }
  45. expect(response.statusCode).to.equal(204)
  46. return cb()
  47. }
  48. )
  49. },
  50. cb => {
  51. return this.user.request(
  52. { url: '/user/emails', json: true },
  53. function(error, response, body) {
  54. expect(response.statusCode).to.equal(200)
  55. expect(body[0].confirmedAt).to.not.exist
  56. expect(body[1].confirmedAt).to.not.exist
  57. return cb()
  58. }
  59. )
  60. },
  61. cb => {
  62. return db.tokens.find(
  63. {
  64. use: 'email_confirmation',
  65. 'data.user_id': this.user._id,
  66. usedAt: { $exists: false }
  67. },
  68. (error, tokens) => {
  69. // There should only be one confirmation token at the moment
  70. expect(tokens.length).to.equal(1)
  71. expect(tokens[0].data.email).to.equal(
  72. 'newly-added-email@example.com'
  73. )
  74. expect(tokens[0].data.user_id).to.equal(this.user._id)
  75. ;({ token } = tokens[0])
  76. return cb()
  77. }
  78. )
  79. },
  80. cb => {
  81. return this.user.request(
  82. {
  83. method: 'POST',
  84. url: '/user/emails/confirm',
  85. json: {
  86. token
  87. }
  88. },
  89. (error, response, body) => {
  90. if (error != null) {
  91. return done(error)
  92. }
  93. expect(response.statusCode).to.equal(200)
  94. return cb()
  95. }
  96. )
  97. },
  98. cb => {
  99. return this.user.request(
  100. { url: '/user/emails', json: true },
  101. function(error, response, body) {
  102. expect(response.statusCode).to.equal(200)
  103. expect(body[0].confirmedAt).to.not.exist
  104. expect(body[1].confirmedAt).to.exist
  105. return cb()
  106. }
  107. )
  108. },
  109. cb => {
  110. return db.tokens.find(
  111. {
  112. use: 'email_confirmation',
  113. 'data.user_id': this.user._id,
  114. usedAt: { $exists: false }
  115. },
  116. (error, tokens) => {
  117. // Token should be deleted after use
  118. expect(tokens.length).to.equal(0)
  119. return cb()
  120. }
  121. )
  122. }
  123. ],
  124. done
  125. )
  126. })
  127. it('should not allow confirmation of the email if the user has changed', function(done) {
  128. let token1 = null
  129. let token2 = null
  130. this.user2 = new User()
  131. this.email = 'duplicate-email@example.com'
  132. return async.series(
  133. [
  134. cb => this.user2.login(cb),
  135. cb => {
  136. // Create email for first user
  137. return this.user.request(
  138. {
  139. method: 'POST',
  140. url: '/user/emails',
  141. json: { email: this.email }
  142. },
  143. cb
  144. )
  145. },
  146. cb => {
  147. return db.tokens.find(
  148. {
  149. use: 'email_confirmation',
  150. 'data.user_id': this.user._id,
  151. usedAt: { $exists: false }
  152. },
  153. (error, tokens) => {
  154. // There should only be one confirmation token at the moment
  155. expect(tokens.length).to.equal(1)
  156. expect(tokens[0].data.email).to.equal(this.email)
  157. expect(tokens[0].data.user_id).to.equal(this.user._id)
  158. token1 = tokens[0].token
  159. return cb()
  160. }
  161. )
  162. },
  163. cb => {
  164. // Delete the email from the first user
  165. return this.user.request(
  166. {
  167. method: 'POST',
  168. url: '/user/emails/delete',
  169. json: { email: this.email }
  170. },
  171. cb
  172. )
  173. },
  174. cb => {
  175. // Create email for second user
  176. return this.user2.request(
  177. {
  178. method: 'POST',
  179. url: '/user/emails',
  180. json: { email: this.email }
  181. },
  182. cb
  183. )
  184. },
  185. cb => {
  186. // Original confirmation token should no longer work
  187. return this.user.request(
  188. {
  189. method: 'POST',
  190. url: '/user/emails/confirm',
  191. json: {
  192. token: token1
  193. }
  194. },
  195. (error, response, body) => {
  196. if (error != null) {
  197. return done(error)
  198. }
  199. expect(response.statusCode).to.equal(404)
  200. return cb()
  201. }
  202. )
  203. },
  204. cb => {
  205. return db.tokens.find(
  206. {
  207. use: 'email_confirmation',
  208. 'data.user_id': this.user2._id,
  209. usedAt: { $exists: false }
  210. },
  211. (error, tokens) => {
  212. // The first token has been used, so this should be token2 now
  213. expect(tokens.length).to.equal(1)
  214. expect(tokens[0].data.email).to.equal(this.email)
  215. expect(tokens[0].data.user_id).to.equal(this.user2._id)
  216. token2 = tokens[0].token
  217. return cb()
  218. }
  219. )
  220. },
  221. cb => {
  222. // Second user should be able to confirm the email
  223. return this.user2.request(
  224. {
  225. method: 'POST',
  226. url: '/user/emails/confirm',
  227. json: {
  228. token: token2
  229. }
  230. },
  231. (error, response, body) => {
  232. if (error != null) {
  233. return done(error)
  234. }
  235. expect(response.statusCode).to.equal(200)
  236. return cb()
  237. }
  238. )
  239. },
  240. cb => {
  241. return this.user2.request(
  242. { url: '/user/emails', json: true },
  243. function(error, response, body) {
  244. expect(response.statusCode).to.equal(200)
  245. expect(body[0].confirmedAt).to.not.exist
  246. expect(body[1].confirmedAt).to.exist
  247. return cb()
  248. }
  249. )
  250. }
  251. ],
  252. done
  253. )
  254. })
  255. })
  256. describe('with an expired token', () =>
  257. it('should not confirm the email', function(done) {
  258. let token = null
  259. return async.series(
  260. [
  261. cb => {
  262. return this.user.request(
  263. {
  264. method: 'POST',
  265. url: '/user/emails',
  266. json: {
  267. email: (this.email = 'expired-token-email@example.com')
  268. }
  269. },
  270. (error, response, body) => {
  271. if (error != null) {
  272. return done(error)
  273. }
  274. expect(response.statusCode).to.equal(204)
  275. return cb()
  276. }
  277. )
  278. },
  279. cb => {
  280. return db.tokens.find(
  281. {
  282. use: 'email_confirmation',
  283. 'data.user_id': this.user._id,
  284. usedAt: { $exists: false }
  285. },
  286. (error, tokens) => {
  287. // There should only be one confirmation token at the moment
  288. expect(tokens.length).to.equal(1)
  289. expect(tokens[0].data.email).to.equal(this.email)
  290. expect(tokens[0].data.user_id).to.equal(this.user._id)
  291. ;({ token } = tokens[0])
  292. return cb()
  293. }
  294. )
  295. },
  296. cb => {
  297. return db.tokens.update(
  298. {
  299. token
  300. },
  301. {
  302. $set: {
  303. expiresAt: new Date(Date.now() - 1000000)
  304. }
  305. },
  306. cb
  307. )
  308. },
  309. cb => {
  310. return this.user.request(
  311. {
  312. method: 'POST',
  313. url: '/user/emails/confirm',
  314. json: {
  315. token
  316. }
  317. },
  318. (error, response, body) => {
  319. if (error != null) {
  320. return done(error)
  321. }
  322. expect(response.statusCode).to.equal(404)
  323. return cb()
  324. }
  325. )
  326. }
  327. ],
  328. done
  329. )
  330. }))
  331. describe('resending the confirmation', function() {
  332. it('should generate a new token', function(done) {
  333. return async.series(
  334. [
  335. cb => {
  336. return this.user.request(
  337. {
  338. method: 'POST',
  339. url: '/user/emails',
  340. json: {
  341. email: 'reconfirmation-email@example.com'
  342. }
  343. },
  344. (error, response, body) => {
  345. if (error != null) {
  346. return done(error)
  347. }
  348. expect(response.statusCode).to.equal(204)
  349. return cb()
  350. }
  351. )
  352. },
  353. cb => {
  354. return db.tokens.find(
  355. {
  356. use: 'email_confirmation',
  357. 'data.user_id': this.user._id,
  358. usedAt: { $exists: false }
  359. },
  360. (error, tokens) => {
  361. // There should only be one confirmation token at the moment
  362. expect(tokens.length).to.equal(1)
  363. expect(tokens[0].data.email).to.equal(
  364. 'reconfirmation-email@example.com'
  365. )
  366. expect(tokens[0].data.user_id).to.equal(this.user._id)
  367. return cb()
  368. }
  369. )
  370. },
  371. cb => {
  372. return this.user.request(
  373. {
  374. method: 'POST',
  375. url: '/user/emails/resend_confirmation',
  376. json: {
  377. email: 'reconfirmation-email@example.com'
  378. }
  379. },
  380. (error, response, body) => {
  381. if (error != null) {
  382. return done(error)
  383. }
  384. expect(response.statusCode).to.equal(200)
  385. return cb()
  386. }
  387. )
  388. },
  389. cb => {
  390. return db.tokens.find(
  391. {
  392. use: 'email_confirmation',
  393. 'data.user_id': this.user._id,
  394. usedAt: { $exists: false }
  395. },
  396. (error, tokens) => {
  397. // There should be two tokens now
  398. expect(tokens.length).to.equal(2)
  399. expect(tokens[0].data.email).to.equal(
  400. 'reconfirmation-email@example.com'
  401. )
  402. expect(tokens[0].data.user_id).to.equal(this.user._id)
  403. expect(tokens[1].data.email).to.equal(
  404. 'reconfirmation-email@example.com'
  405. )
  406. expect(tokens[1].data.user_id).to.equal(this.user._id)
  407. return cb()
  408. }
  409. )
  410. }
  411. ],
  412. done
  413. )
  414. })
  415. it('should create a new token if none exists', function(done) {
  416. // This should only be for users that have sign up with their main
  417. // emails before the confirmation system existed
  418. return async.series(
  419. [
  420. cb => {
  421. return db.tokens.remove(
  422. {
  423. use: 'email_confirmation',
  424. 'data.user_id': this.user._id,
  425. usedAt: { $exists: false }
  426. },
  427. cb
  428. )
  429. },
  430. cb => {
  431. return this.user.request(
  432. {
  433. method: 'POST',
  434. url: '/user/emails/resend_confirmation',
  435. json: {
  436. email: this.user.email
  437. }
  438. },
  439. (error, response, body) => {
  440. if (error != null) {
  441. return done(error)
  442. }
  443. expect(response.statusCode).to.equal(200)
  444. return cb()
  445. }
  446. )
  447. },
  448. cb => {
  449. return db.tokens.find(
  450. {
  451. use: 'email_confirmation',
  452. 'data.user_id': this.user._id,
  453. usedAt: { $exists: false }
  454. },
  455. (error, tokens) => {
  456. // There should still only be one confirmation token
  457. expect(tokens.length).to.equal(1)
  458. expect(tokens[0].data.email).to.equal(this.user.email)
  459. expect(tokens[0].data.user_id).to.equal(this.user._id)
  460. return cb()
  461. }
  462. )
  463. }
  464. ],
  465. done
  466. )
  467. })
  468. it("should not allow reconfirmation if the email doesn't match the user", function(done) {
  469. return async.series(
  470. [
  471. cb => {
  472. return this.user.request(
  473. {
  474. method: 'POST',
  475. url: '/user/emails/resend_confirmation',
  476. json: {
  477. email: 'non-matching-email@example.com'
  478. }
  479. },
  480. (error, response, body) => {
  481. if (error != null) {
  482. return done(error)
  483. }
  484. expect(response.statusCode).to.equal(422)
  485. return cb()
  486. }
  487. )
  488. },
  489. cb => {
  490. return db.tokens.find(
  491. {
  492. use: 'email_confirmation',
  493. 'data.user_id': this.user._id,
  494. usedAt: { $exists: false }
  495. },
  496. (error, tokens) => {
  497. expect(tokens.length).to.equal(0)
  498. return cb()
  499. }
  500. )
  501. }
  502. ],
  503. done
  504. )
  505. })
  506. })
  507. describe('setting a default email', function() {
  508. it('should update confirmed emails for users not in v1', function(done) {
  509. const token = null
  510. return async.series(
  511. [
  512. cb => {
  513. return this.user.request(
  514. {
  515. method: 'POST',
  516. url: '/user/emails',
  517. json: {
  518. email: 'new-confirmed-default@example.com'
  519. }
  520. },
  521. (error, response, body) => {
  522. if (error != null) {
  523. return done(error)
  524. }
  525. expect(response.statusCode).to.equal(204)
  526. return cb()
  527. }
  528. )
  529. },
  530. cb => {
  531. // Mark the email as confirmed
  532. return db.users.update(
  533. {
  534. 'emails.email': 'new-confirmed-default@example.com'
  535. },
  536. {
  537. $set: {
  538. 'emails.$.confirmedAt': new Date()
  539. }
  540. },
  541. cb
  542. )
  543. },
  544. cb => {
  545. return this.user.request(
  546. {
  547. method: 'POST',
  548. url: '/user/emails/default',
  549. json: {
  550. email: 'new-confirmed-default@example.com'
  551. }
  552. },
  553. (error, response, body) => {
  554. if (error != null) {
  555. return done(error)
  556. }
  557. expect(response.statusCode).to.equal(200)
  558. return cb()
  559. }
  560. )
  561. },
  562. cb => {
  563. return this.user.request(
  564. { url: '/user/emails', json: true },
  565. function(error, response, body) {
  566. expect(response.statusCode).to.equal(200)
  567. expect(body[0].confirmedAt).to.not.exist
  568. expect(body[0].default).to.equal(false)
  569. expect(body[1].confirmedAt).to.exist
  570. expect(body[1].default).to.equal(true)
  571. return cb()
  572. }
  573. )
  574. }
  575. ],
  576. done
  577. )
  578. })
  579. it('should not allow changing unconfirmed emails in v1', function(done) {
  580. const token = null
  581. return async.series(
  582. [
  583. cb => {
  584. return db.users.update(
  585. {
  586. _id: ObjectId(this.user._id)
  587. },
  588. {
  589. $set: {
  590. 'overleaf.id': 42
  591. }
  592. },
  593. cb
  594. )
  595. },
  596. cb => {
  597. return this.user.request(
  598. {
  599. method: 'POST',
  600. url: '/user/emails',
  601. json: {
  602. email: 'new-unconfirmed-default@example.com'
  603. }
  604. },
  605. (error, response, body) => {
  606. if (error != null) {
  607. return done(error)
  608. }
  609. expect(response.statusCode).to.equal(204)
  610. return cb()
  611. }
  612. )
  613. },
  614. cb => {
  615. return this.user.request(
  616. {
  617. method: 'POST',
  618. url: '/user/emails/default',
  619. json: {
  620. email: 'new-unconfirmed-default@example.com'
  621. }
  622. },
  623. (error, response, body) => {
  624. if (error != null) {
  625. return done(error)
  626. }
  627. expect(response.statusCode).to.equal(409)
  628. return cb()
  629. }
  630. )
  631. },
  632. cb => {
  633. return this.user.request(
  634. { url: '/user/emails', json: true },
  635. function(error, response, body) {
  636. expect(body[0].default).to.equal(true)
  637. expect(body[1].default).to.equal(false)
  638. return cb()
  639. }
  640. )
  641. }
  642. ],
  643. done
  644. )
  645. })
  646. it('should update the email in v1 if confirmed', function(done) {
  647. const token = null
  648. return async.series(
  649. [
  650. cb => {
  651. return db.users.update(
  652. {
  653. _id: ObjectId(this.user._id)
  654. },
  655. {
  656. $set: {
  657. 'overleaf.id': 42
  658. }
  659. },
  660. cb
  661. )
  662. },
  663. cb => {
  664. return this.user.request(
  665. {
  666. method: 'POST',
  667. url: '/user/emails',
  668. json: {
  669. email: 'new-confirmed-default-in-v1@example.com'
  670. }
  671. },
  672. (error, response, body) => {
  673. if (error != null) {
  674. return done(error)
  675. }
  676. expect(response.statusCode).to.equal(204)
  677. return cb()
  678. }
  679. )
  680. },
  681. cb => {
  682. // Mark the email as confirmed
  683. return db.users.update(
  684. {
  685. 'emails.email': 'new-confirmed-default-in-v1@example.com'
  686. },
  687. {
  688. $set: {
  689. 'emails.$.confirmedAt': new Date()
  690. }
  691. },
  692. cb
  693. )
  694. },
  695. cb => {
  696. return this.user.request(
  697. {
  698. method: 'POST',
  699. url: '/user/emails/default',
  700. json: {
  701. email: 'new-confirmed-default-in-v1@example.com'
  702. }
  703. },
  704. (error, response, body) => {
  705. if (error != null) {
  706. return done(error)
  707. }
  708. expect(response.statusCode).to.equal(200)
  709. return cb()
  710. }
  711. )
  712. }
  713. ],
  714. error => {
  715. if (error != null) {
  716. return done(error)
  717. }
  718. expect(
  719. MockV1Api.updateEmail.calledWith(
  720. 42,
  721. 'new-confirmed-default-in-v1@example.com'
  722. )
  723. ).to.equal(true)
  724. return done()
  725. }
  726. )
  727. })
  728. it('should return an error if the email exists in v1', function(done) {
  729. MockV1Api.existingEmails.push('exists-in-v1@example.com')
  730. return async.series(
  731. [
  732. cb => {
  733. return db.users.update(
  734. {
  735. _id: ObjectId(this.user._id)
  736. },
  737. {
  738. $set: {
  739. 'overleaf.id': 42
  740. }
  741. },
  742. cb
  743. )
  744. },
  745. cb => {
  746. return this.user.request(
  747. {
  748. method: 'POST',
  749. url: '/user/emails',
  750. json: {
  751. email: 'exists-in-v1@example.com'
  752. }
  753. },
  754. (error, response, body) => {
  755. if (error != null) {
  756. return done(error)
  757. }
  758. expect(response.statusCode).to.equal(204)
  759. return cb()
  760. }
  761. )
  762. },
  763. cb => {
  764. // Mark the email as confirmed
  765. return db.users.update(
  766. {
  767. 'emails.email': 'exists-in-v1@example.com'
  768. },
  769. {
  770. $set: {
  771. 'emails.$.confirmedAt': new Date()
  772. }
  773. },
  774. cb
  775. )
  776. },
  777. cb => {
  778. return this.user.request(
  779. {
  780. method: 'POST',
  781. url: '/user/emails/default',
  782. json: {
  783. email: 'exists-in-v1@example.com'
  784. }
  785. },
  786. (error, response, body) => {
  787. if (error != null) {
  788. return done(error)
  789. }
  790. expect(response.statusCode).to.equal(409)
  791. expect(body).to.deep.equal({
  792. message: 'This email is already registered'
  793. })
  794. return cb()
  795. }
  796. )
  797. },
  798. cb => {
  799. return this.user.request(
  800. { url: '/user/emails', json: true },
  801. function(error, response, body) {
  802. expect(body[0].default).to.equal(true)
  803. expect(body[1].default).to.equal(false)
  804. return cb()
  805. }
  806. )
  807. }
  808. ],
  809. done
  810. )
  811. })
  812. })
  813. })