UserEmailsTests.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  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. (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. (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. (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', function() {
  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. })
  332. describe('resending the confirmation', function() {
  333. it('should generate a new token', function(done) {
  334. return async.series(
  335. [
  336. cb => {
  337. return this.user.request(
  338. {
  339. method: 'POST',
  340. url: '/user/emails',
  341. json: {
  342. email: 'reconfirmation-email@example.com'
  343. }
  344. },
  345. (error, response, body) => {
  346. if (error != null) {
  347. return done(error)
  348. }
  349. expect(response.statusCode).to.equal(204)
  350. return cb()
  351. }
  352. )
  353. },
  354. cb => {
  355. return db.tokens.find(
  356. {
  357. use: 'email_confirmation',
  358. 'data.user_id': this.user._id,
  359. usedAt: { $exists: false }
  360. },
  361. (error, tokens) => {
  362. // There should only be one confirmation token at the moment
  363. expect(tokens.length).to.equal(1)
  364. expect(tokens[0].data.email).to.equal(
  365. 'reconfirmation-email@example.com'
  366. )
  367. expect(tokens[0].data.user_id).to.equal(this.user._id)
  368. return cb()
  369. }
  370. )
  371. },
  372. cb => {
  373. return this.user.request(
  374. {
  375. method: 'POST',
  376. url: '/user/emails/resend_confirmation',
  377. json: {
  378. email: 'reconfirmation-email@example.com'
  379. }
  380. },
  381. (error, response, body) => {
  382. if (error != null) {
  383. return done(error)
  384. }
  385. expect(response.statusCode).to.equal(200)
  386. return cb()
  387. }
  388. )
  389. },
  390. cb => {
  391. return db.tokens.find(
  392. {
  393. use: 'email_confirmation',
  394. 'data.user_id': this.user._id,
  395. usedAt: { $exists: false }
  396. },
  397. (error, tokens) => {
  398. // There should be two tokens now
  399. expect(tokens.length).to.equal(2)
  400. expect(tokens[0].data.email).to.equal(
  401. 'reconfirmation-email@example.com'
  402. )
  403. expect(tokens[0].data.user_id).to.equal(this.user._id)
  404. expect(tokens[1].data.email).to.equal(
  405. 'reconfirmation-email@example.com'
  406. )
  407. expect(tokens[1].data.user_id).to.equal(this.user._id)
  408. return cb()
  409. }
  410. )
  411. }
  412. ],
  413. done
  414. )
  415. })
  416. it('should create a new token if none exists', function(done) {
  417. // This should only be for users that have sign up with their main
  418. // emails before the confirmation system existed
  419. return async.series(
  420. [
  421. cb => {
  422. return db.tokens.remove(
  423. {
  424. use: 'email_confirmation',
  425. 'data.user_id': this.user._id,
  426. usedAt: { $exists: false }
  427. },
  428. cb
  429. )
  430. },
  431. cb => {
  432. return this.user.request(
  433. {
  434. method: 'POST',
  435. url: '/user/emails/resend_confirmation',
  436. json: {
  437. email: this.user.email
  438. }
  439. },
  440. (error, response, body) => {
  441. if (error != null) {
  442. return done(error)
  443. }
  444. expect(response.statusCode).to.equal(200)
  445. return cb()
  446. }
  447. )
  448. },
  449. cb => {
  450. return db.tokens.find(
  451. {
  452. use: 'email_confirmation',
  453. 'data.user_id': this.user._id,
  454. usedAt: { $exists: false }
  455. },
  456. (error, tokens) => {
  457. // There should still only be one confirmation token
  458. expect(tokens.length).to.equal(1)
  459. expect(tokens[0].data.email).to.equal(this.user.email)
  460. expect(tokens[0].data.user_id).to.equal(this.user._id)
  461. return cb()
  462. }
  463. )
  464. }
  465. ],
  466. done
  467. )
  468. })
  469. it("should not allow reconfirmation if the email doesn't match the user", function(done) {
  470. return async.series(
  471. [
  472. cb => {
  473. return this.user.request(
  474. {
  475. method: 'POST',
  476. url: '/user/emails/resend_confirmation',
  477. json: {
  478. email: 'non-matching-email@example.com'
  479. }
  480. },
  481. (error, response, body) => {
  482. if (error != null) {
  483. return done(error)
  484. }
  485. expect(response.statusCode).to.equal(422)
  486. return cb()
  487. }
  488. )
  489. },
  490. cb => {
  491. return db.tokens.find(
  492. {
  493. use: 'email_confirmation',
  494. 'data.user_id': this.user._id,
  495. usedAt: { $exists: false }
  496. },
  497. (error, tokens) => {
  498. expect(tokens.length).to.equal(0)
  499. return cb()
  500. }
  501. )
  502. }
  503. ],
  504. done
  505. )
  506. })
  507. })
  508. describe('setting a default email', function() {
  509. it('should update confirmed emails for users not in v1', function(done) {
  510. const token = null
  511. return async.series(
  512. [
  513. cb => {
  514. return this.user.request(
  515. {
  516. method: 'POST',
  517. url: '/user/emails',
  518. json: {
  519. email: 'new-confirmed-default@example.com'
  520. }
  521. },
  522. (error, response, body) => {
  523. if (error != null) {
  524. return done(error)
  525. }
  526. expect(response.statusCode).to.equal(204)
  527. return cb()
  528. }
  529. )
  530. },
  531. cb => {
  532. // Mark the email as confirmed
  533. return db.users.update(
  534. {
  535. 'emails.email': 'new-confirmed-default@example.com'
  536. },
  537. {
  538. $set: {
  539. 'emails.$.confirmedAt': new Date()
  540. }
  541. },
  542. cb
  543. )
  544. },
  545. cb => {
  546. return this.user.request(
  547. {
  548. method: 'POST',
  549. url: '/user/emails/default',
  550. json: {
  551. email: 'new-confirmed-default@example.com'
  552. }
  553. },
  554. (error, response, body) => {
  555. if (error != null) {
  556. return done(error)
  557. }
  558. expect(response.statusCode).to.equal(200)
  559. return cb()
  560. }
  561. )
  562. },
  563. cb => {
  564. return this.user.request(
  565. { url: '/user/emails', json: true },
  566. (error, response, body) => {
  567. expect(response.statusCode).to.equal(200)
  568. expect(body[0].confirmedAt).to.not.exist
  569. expect(body[0].default).to.equal(false)
  570. expect(body[1].confirmedAt).to.exist
  571. expect(body[1].default).to.equal(true)
  572. return cb()
  573. }
  574. )
  575. }
  576. ],
  577. done
  578. )
  579. })
  580. it('should not allow changing unconfirmed emails in v1', function(done) {
  581. const token = null
  582. return async.series(
  583. [
  584. cb => {
  585. return db.users.update(
  586. {
  587. _id: ObjectId(this.user._id)
  588. },
  589. {
  590. $set: {
  591. 'overleaf.id': 42
  592. }
  593. },
  594. cb
  595. )
  596. },
  597. cb => {
  598. return this.user.request(
  599. {
  600. method: 'POST',
  601. url: '/user/emails',
  602. json: {
  603. email: 'new-unconfirmed-default@example.com'
  604. }
  605. },
  606. (error, response, body) => {
  607. if (error != null) {
  608. return done(error)
  609. }
  610. expect(response.statusCode).to.equal(204)
  611. return cb()
  612. }
  613. )
  614. },
  615. cb => {
  616. return this.user.request(
  617. {
  618. method: 'POST',
  619. url: '/user/emails/default',
  620. json: {
  621. email: 'new-unconfirmed-default@example.com'
  622. }
  623. },
  624. (error, response, body) => {
  625. if (error != null) {
  626. return done(error)
  627. }
  628. expect(response.statusCode).to.equal(409)
  629. return cb()
  630. }
  631. )
  632. },
  633. cb => {
  634. return this.user.request(
  635. { url: '/user/emails', json: true },
  636. (error, response, body) => {
  637. expect(body[0].default).to.equal(true)
  638. expect(body[1].default).to.equal(false)
  639. return cb()
  640. }
  641. )
  642. }
  643. ],
  644. done
  645. )
  646. })
  647. it('should not update the email in v1', function(done) {
  648. const token = null
  649. return async.series(
  650. [
  651. cb => {
  652. return db.users.update(
  653. {
  654. _id: ObjectId(this.user._id)
  655. },
  656. {
  657. $set: {
  658. 'overleaf.id': 42
  659. }
  660. },
  661. cb
  662. )
  663. },
  664. cb => {
  665. return this.user.request(
  666. {
  667. method: 'POST',
  668. url: '/user/emails',
  669. json: {
  670. email: 'new-confirmed-default-in-v1@example.com'
  671. }
  672. },
  673. (error, response, body) => {
  674. if (error != null) {
  675. return done(error)
  676. }
  677. expect(response.statusCode).to.equal(204)
  678. return cb()
  679. }
  680. )
  681. },
  682. cb => {
  683. // Mark the email as confirmed
  684. return db.users.update(
  685. {
  686. 'emails.email': 'new-confirmed-default-in-v1@example.com'
  687. },
  688. {
  689. $set: {
  690. 'emails.$.confirmedAt': new Date()
  691. }
  692. },
  693. cb
  694. )
  695. },
  696. cb => {
  697. return this.user.request(
  698. {
  699. method: 'POST',
  700. url: '/user/emails/default',
  701. json: {
  702. email: 'new-confirmed-default-in-v1@example.com'
  703. }
  704. },
  705. (error, response, body) => {
  706. if (error != null) {
  707. return done(error)
  708. }
  709. expect(response.statusCode).to.equal(200)
  710. return cb()
  711. }
  712. )
  713. }
  714. ],
  715. error => {
  716. if (error != null) {
  717. return done(error)
  718. }
  719. expect(MockV1Api.updateEmail.callCount).to.equal(0)
  720. done()
  721. }
  722. )
  723. })
  724. it('should not return an error if the email exists in v1', function(done) {
  725. MockV1Api.existingEmails.push('exists-in-v1@example.com')
  726. return async.series(
  727. [
  728. cb => {
  729. return db.users.update(
  730. {
  731. _id: ObjectId(this.user._id)
  732. },
  733. {
  734. $set: {
  735. 'overleaf.id': 42
  736. }
  737. },
  738. cb
  739. )
  740. },
  741. cb => {
  742. return this.user.request(
  743. {
  744. method: 'POST',
  745. url: '/user/emails',
  746. json: {
  747. email: 'exists-in-v1@example.com'
  748. }
  749. },
  750. (error, response, body) => {
  751. if (error != null) {
  752. return done(error)
  753. }
  754. expect(response.statusCode).to.equal(204)
  755. return cb()
  756. }
  757. )
  758. },
  759. cb => {
  760. // Mark the email as confirmed
  761. return db.users.update(
  762. {
  763. 'emails.email': 'exists-in-v1@example.com'
  764. },
  765. {
  766. $set: {
  767. 'emails.$.confirmedAt': new Date()
  768. }
  769. },
  770. cb
  771. )
  772. },
  773. cb => {
  774. return this.user.request(
  775. {
  776. method: 'POST',
  777. url: '/user/emails/default',
  778. json: {
  779. email: 'exists-in-v1@example.com'
  780. }
  781. },
  782. (error, response, body) => {
  783. if (error != null) {
  784. return done(error)
  785. }
  786. expect(response.statusCode).to.equal(200)
  787. cb()
  788. }
  789. )
  790. },
  791. cb => {
  792. return this.user.request(
  793. { url: '/user/emails', json: true },
  794. (error, response, body) => {
  795. expect(body[0].default).to.equal(false)
  796. expect(body[1].default).to.equal(true)
  797. return cb()
  798. }
  799. )
  800. }
  801. ],
  802. done
  803. )
  804. })
  805. })
  806. })