| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 |
- expect = require("chai").expect
- async = require("async")
- User = require "./helpers/User"
- request = require "./helpers/request"
- settings = require "settings-sharelatex"
- {db, ObjectId} = require("../../../app/js/infrastructure/mongojs")
- MockV1Api = require "./helpers/MockV1Api"
- describe "UserEmails", ->
- beforeEach (done) ->
- @timeout(20000)
- @user = new User()
- @user.login done
- describe 'confirming an email', ->
- it 'should confirm the email', (done) ->
- token = null
- async.series [
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails',
- json:
- email: 'newly-added-email@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 204
- cb()
- (cb) =>
- @user.request { url: '/user/emails', json: true }, (error, response, body) ->
- expect(response.statusCode).to.equal 200
- expect(body[0].confirmedAt).to.not.exist
- expect(body[1].confirmedAt).to.not.exist
- cb()
- (cb) =>
- db.tokens.find {
- use: 'email_confirmation',
- 'data.user_id': @user._id,
- usedAt: { $exists: false }
- }, (error, tokens) =>
- # There should only be one confirmation token at the moment
- expect(tokens.length).to.equal 1
- expect(tokens[0].data.email).to.equal 'newly-added-email@example.com'
- expect(tokens[0].data.user_id).to.equal @user._id
- token = tokens[0].token
- cb()
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails/confirm',
- json:
- token: token
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 200
- cb()
- (cb) =>
- @user.request { url: '/user/emails', json: true }, (error, response, body) ->
- expect(response.statusCode).to.equal 200
- expect(body[0].confirmedAt).to.not.exist
- expect(body[1].confirmedAt).to.exist
- cb()
- (cb) =>
- db.tokens.find {
- use: 'email_confirmation',
- 'data.user_id': @user._id,
- usedAt: { $exists: false }
- }, (error, tokens) =>
- # Token should be deleted after use
- expect(tokens.length).to.equal 0
- cb()
- ], done
- it 'should not allow confirmation of the email if the user has changed', (done) ->
- token1 = null
- token2 = null
- @user2 = new User()
- @email = 'duplicate-email@example.com'
- async.series [
- (cb) => @user2.login cb
- (cb) =>
- # Create email for first user
- @user.request {
- method: 'POST',
- url: '/user/emails',
- json: {@email}
- }, cb
- (cb) =>
- db.tokens.find {
- use: 'email_confirmation',
- 'data.user_id': @user._id,
- usedAt: { $exists: false }
- }, (error, tokens) =>
- # There should only be one confirmation token at the moment
- expect(tokens.length).to.equal 1
- expect(tokens[0].data.email).to.equal @email
- expect(tokens[0].data.user_id).to.equal @user._id
- token1 = tokens[0].token
- cb()
- (cb) =>
- # Delete the email from the first user
- @user.request {
- method: 'POST',
- url: '/user/emails/delete',
- json: {@email}
- }, cb
- (cb) =>
- # Create email for second user
- @user2.request {
- method: 'POST',
- url: '/user/emails',
- json: {@email}
- }, cb
- (cb) =>
- # Original confirmation token should no longer work
- @user.request {
- method: 'POST',
- url: '/user/emails/confirm',
- json:
- token: token1
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 404
- cb()
- (cb) =>
- db.tokens.find {
- use: 'email_confirmation',
- 'data.user_id': @user2._id,
- usedAt: { $exists: false }
- }, (error, tokens) =>
- # The first token has been used, so this should be token2 now
- expect(tokens.length).to.equal 1
- expect(tokens[0].data.email).to.equal @email
- expect(tokens[0].data.user_id).to.equal @user2._id
- token2 = tokens[0].token
- cb()
- (cb) =>
- # Second user should be able to confirm the email
- @user2.request {
- method: 'POST',
- url: '/user/emails/confirm',
- json:
- token: token2
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 200
- cb()
- (cb) =>
- @user2.request { url: '/user/emails', json: true }, (error, response, body) ->
- expect(response.statusCode).to.equal 200
- expect(body[0].confirmedAt).to.not.exist
- expect(body[1].confirmedAt).to.exist
- cb()
- ], done
- describe "with an expired token", ->
- it 'should not confirm the email', (done) ->
- token = null
- async.series [
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails',
- json:
- email: @email = 'expired-token-email@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 204
- cb()
- (cb) =>
- db.tokens.find {
- use: 'email_confirmation',
- 'data.user_id': @user._id,
- usedAt: { $exists: false }
- }, (error, tokens) =>
- # There should only be one confirmation token at the moment
- expect(tokens.length).to.equal 1
- expect(tokens[0].data.email).to.equal @email
- expect(tokens[0].data.user_id).to.equal @user._id
- token = tokens[0].token
- cb()
- (cb) =>
- db.tokens.update {
- token: token
- }, {
- $set: {
- expiresAt: new Date(Date.now() - 1000000)
- }
- }, cb
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails/confirm',
- json:
- token: token
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 404
- cb()
- ], done
- describe 'resending the confirmation', ->
- it 'should generate a new token', (done) ->
- async.series [
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails',
- json:
- email: 'reconfirmation-email@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 204
- cb()
- (cb) =>
- db.tokens.find {
- use: 'email_confirmation',
- 'data.user_id': @user._id,
- usedAt: { $exists: false }
- }, (error, tokens) =>
- # There should only be one confirmation token at the moment
- expect(tokens.length).to.equal 1
- expect(tokens[0].data.email).to.equal 'reconfirmation-email@example.com'
- expect(tokens[0].data.user_id).to.equal @user._id
- cb()
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails/resend_confirmation',
- json:
- email: 'reconfirmation-email@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 200
- cb()
- (cb) =>
- db.tokens.find {
- use: 'email_confirmation',
- 'data.user_id': @user._id,
- usedAt: { $exists: false }
- }, (error, tokens) =>
- # There should be two tokens now
- expect(tokens.length).to.equal 2
- expect(tokens[0].data.email).to.equal 'reconfirmation-email@example.com'
- expect(tokens[0].data.user_id).to.equal @user._id
- expect(tokens[1].data.email).to.equal 'reconfirmation-email@example.com'
- expect(tokens[1].data.user_id).to.equal @user._id
- cb()
- ], done
- it 'should create a new token if none exists', (done) ->
- # This should only be for users that have sign up with their main
- # emails before the confirmation system existed
- async.series [
- (cb) =>
- db.tokens.remove {
- use: 'email_confirmation',
- 'data.user_id': @user._id,
- usedAt: { $exists: false }
- }, cb
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails/resend_confirmation',
- json:
- email: @user.email
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 200
- cb()
- (cb) =>
- db.tokens.find {
- use: 'email_confirmation',
- 'data.user_id': @user._id,
- usedAt: { $exists: false }
- }, (error, tokens) =>
- # There should still only be one confirmation token
- expect(tokens.length).to.equal 1
- expect(tokens[0].data.email).to.equal @user.email
- expect(tokens[0].data.user_id).to.equal @user._id
- cb()
- ], done
- it "should not allow reconfirmation if the email doesn't match the user", (done) ->
- async.series [
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails/resend_confirmation',
- json:
- email: 'non-matching-email@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 422
- cb()
- (cb) =>
- db.tokens.find {
- use: 'email_confirmation',
- 'data.user_id': @user._id,
- usedAt: { $exists: false }
- }, (error, tokens) =>
- expect(tokens.length).to.equal 0
- cb()
- ], done
- describe 'setting a default email', ->
- it 'should update confirmed emails for users not in v1', (done) ->
- token = null
- async.series [
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails',
- json:
- email: 'new-confirmed-default@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 204
- cb()
- (cb) =>
- # Mark the email as confirmed
- db.users.update {
- 'emails.email': 'new-confirmed-default@example.com'
- }, {
- $set: {
- 'emails.$.confirmedAt': new Date()
- }
- }, cb
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails/default',
- json:
- email: 'new-confirmed-default@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 200
- cb()
- (cb) =>
- @user.request { url: '/user/emails', json: true }, (error, response, body) ->
- expect(response.statusCode).to.equal 200
- expect(body[0].confirmedAt).to.not.exist
- expect(body[0].default).to.equal false
- expect(body[1].confirmedAt).to.exist
- expect(body[1].default).to.equal true
- cb()
- ], done
- it 'should not allow changing unconfirmed emails in v1', (done) ->
- token = null
- async.series [
- (cb) =>
- db.users.update {
- _id: ObjectId(@user._id)
- }, {
- $set: {
- 'overleaf.id': 42
- }
- }, cb
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails',
- json:
- email: 'new-unconfirmed-default@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 204
- cb()
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails/default',
- json:
- email: 'new-unconfirmed-default@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 409
- cb()
- (cb) =>
- @user.request { url: '/user/emails', json: true }, (error, response, body) ->
- expect(body[0].default).to.equal true
- expect(body[1].default).to.equal false
- cb()
- ], done
- it 'should update the email in v1 if confirmed', (done) ->
- token = null
- async.series [
- (cb) =>
- db.users.update {
- _id: ObjectId(@user._id)
- }, {
- $set: {
- 'overleaf.id': 42
- }
- }, cb
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails',
- json:
- email: 'new-confirmed-default-in-v1@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 204
- cb()
- (cb) =>
- # Mark the email as confirmed
- db.users.update {
- 'emails.email': 'new-confirmed-default-in-v1@example.com'
- }, {
- $set: {
- 'emails.$.confirmedAt': new Date()
- }
- }, cb
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails/default',
- json:
- email: 'new-confirmed-default-in-v1@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 200
- cb()
- ], (error) =>
- return done(error) if error?
- expect(
- MockV1Api.updateEmail.calledWith(42, 'new-confirmed-default-in-v1@example.com')
- ).to.equal true
- done()
- it 'should return an error if the email exists in v1', (done) ->
- MockV1Api.existingEmails.push 'exists-in-v1@example.com'
- async.series [
- (cb) =>
- db.users.update {
- _id: ObjectId(@user._id)
- }, {
- $set: {
- 'overleaf.id': 42
- }
- }, cb
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails',
- json:
- email: 'exists-in-v1@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 204
- cb()
- (cb) =>
- # Mark the email as confirmed
- db.users.update {
- 'emails.email': 'exists-in-v1@example.com'
- }, {
- $set: {
- 'emails.$.confirmedAt': new Date()
- }
- }, cb
- (cb) =>
- @user.request {
- method: 'POST',
- url: '/user/emails/default',
- json:
- email: 'exists-in-v1@example.com'
- }, (error, response, body) =>
- return done(error) if error?
- expect(response.statusCode).to.equal 409
- expect(body).to.deep.equal {
- message: "This email is already registered"
- }
- cb()
- (cb) =>
- @user.request { url: '/user/emails', json: true }, (error, response, body) ->
- expect(body[0].default).to.equal true
- expect(body[1].default).to.equal false
- cb()
- ], done
|