UserEmailsTests.coffee 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. expect = require("chai").expect
  2. async = require("async")
  3. User = require "./helpers/User"
  4. request = require "./helpers/request"
  5. settings = require "settings-sharelatex"
  6. {db, ObjectId} = require("../../../app/js/infrastructure/mongojs")
  7. MockV1Api = require "./helpers/MockV1Api"
  8. describe "UserEmails", ->
  9. beforeEach (done) ->
  10. @timeout(20000)
  11. @user = new User()
  12. @user.login done
  13. describe 'confirming an email', ->
  14. it 'should confirm the email', (done) ->
  15. token = null
  16. async.series [
  17. (cb) =>
  18. @user.request {
  19. method: 'POST',
  20. url: '/user/emails',
  21. json:
  22. email: 'newly-added-email@example.com'
  23. }, (error, response, body) =>
  24. return done(error) if error?
  25. expect(response.statusCode).to.equal 204
  26. cb()
  27. (cb) =>
  28. @user.request { url: '/user/emails', json: true }, (error, response, body) ->
  29. expect(response.statusCode).to.equal 200
  30. expect(body[0].confirmedAt).to.not.exist
  31. expect(body[1].confirmedAt).to.not.exist
  32. cb()
  33. (cb) =>
  34. db.tokens.find {
  35. use: 'email_confirmation',
  36. 'data.user_id': @user._id,
  37. usedAt: { $exists: false }
  38. }, (error, tokens) =>
  39. # There should only be one confirmation token at the moment
  40. expect(tokens.length).to.equal 1
  41. expect(tokens[0].data.email).to.equal 'newly-added-email@example.com'
  42. expect(tokens[0].data.user_id).to.equal @user._id
  43. token = tokens[0].token
  44. cb()
  45. (cb) =>
  46. @user.request {
  47. method: 'POST',
  48. url: '/user/emails/confirm',
  49. json:
  50. token: token
  51. }, (error, response, body) =>
  52. return done(error) if error?
  53. expect(response.statusCode).to.equal 200
  54. cb()
  55. (cb) =>
  56. @user.request { url: '/user/emails', json: true }, (error, response, body) ->
  57. expect(response.statusCode).to.equal 200
  58. expect(body[0].confirmedAt).to.not.exist
  59. expect(body[1].confirmedAt).to.exist
  60. cb()
  61. (cb) =>
  62. db.tokens.find {
  63. use: 'email_confirmation',
  64. 'data.user_id': @user._id,
  65. usedAt: { $exists: false }
  66. }, (error, tokens) =>
  67. # Token should be deleted after use
  68. expect(tokens.length).to.equal 0
  69. cb()
  70. ], done
  71. it 'should not allow confirmation of the email if the user has changed', (done) ->
  72. token1 = null
  73. token2 = null
  74. @user2 = new User()
  75. @email = 'duplicate-email@example.com'
  76. async.series [
  77. (cb) => @user2.login cb
  78. (cb) =>
  79. # Create email for first user
  80. @user.request {
  81. method: 'POST',
  82. url: '/user/emails',
  83. json: {@email}
  84. }, cb
  85. (cb) =>
  86. db.tokens.find {
  87. use: 'email_confirmation',
  88. 'data.user_id': @user._id,
  89. usedAt: { $exists: false }
  90. }, (error, tokens) =>
  91. # There should only be one confirmation token at the moment
  92. expect(tokens.length).to.equal 1
  93. expect(tokens[0].data.email).to.equal @email
  94. expect(tokens[0].data.user_id).to.equal @user._id
  95. token1 = tokens[0].token
  96. cb()
  97. (cb) =>
  98. # Delete the email from the first user
  99. @user.request {
  100. method: 'POST',
  101. url: '/user/emails/delete',
  102. json: {@email}
  103. }, cb
  104. (cb) =>
  105. # Create email for second user
  106. @user2.request {
  107. method: 'POST',
  108. url: '/user/emails',
  109. json: {@email}
  110. }, cb
  111. (cb) =>
  112. # Original confirmation token should no longer work
  113. @user.request {
  114. method: 'POST',
  115. url: '/user/emails/confirm',
  116. json:
  117. token: token1
  118. }, (error, response, body) =>
  119. return done(error) if error?
  120. expect(response.statusCode).to.equal 404
  121. cb()
  122. (cb) =>
  123. db.tokens.find {
  124. use: 'email_confirmation',
  125. 'data.user_id': @user2._id,
  126. usedAt: { $exists: false }
  127. }, (error, tokens) =>
  128. # The first token has been used, so this should be token2 now
  129. expect(tokens.length).to.equal 1
  130. expect(tokens[0].data.email).to.equal @email
  131. expect(tokens[0].data.user_id).to.equal @user2._id
  132. token2 = tokens[0].token
  133. cb()
  134. (cb) =>
  135. # Second user should be able to confirm the email
  136. @user2.request {
  137. method: 'POST',
  138. url: '/user/emails/confirm',
  139. json:
  140. token: token2
  141. }, (error, response, body) =>
  142. return done(error) if error?
  143. expect(response.statusCode).to.equal 200
  144. cb()
  145. (cb) =>
  146. @user2.request { url: '/user/emails', json: true }, (error, response, body) ->
  147. expect(response.statusCode).to.equal 200
  148. expect(body[0].confirmedAt).to.not.exist
  149. expect(body[1].confirmedAt).to.exist
  150. cb()
  151. ], done
  152. describe "with an expired token", ->
  153. it 'should not confirm the email', (done) ->
  154. token = null
  155. async.series [
  156. (cb) =>
  157. @user.request {
  158. method: 'POST',
  159. url: '/user/emails',
  160. json:
  161. email: @email = 'expired-token-email@example.com'
  162. }, (error, response, body) =>
  163. return done(error) if error?
  164. expect(response.statusCode).to.equal 204
  165. cb()
  166. (cb) =>
  167. db.tokens.find {
  168. use: 'email_confirmation',
  169. 'data.user_id': @user._id,
  170. usedAt: { $exists: false }
  171. }, (error, tokens) =>
  172. # There should only be one confirmation token at the moment
  173. expect(tokens.length).to.equal 1
  174. expect(tokens[0].data.email).to.equal @email
  175. expect(tokens[0].data.user_id).to.equal @user._id
  176. token = tokens[0].token
  177. cb()
  178. (cb) =>
  179. db.tokens.update {
  180. token: token
  181. }, {
  182. $set: {
  183. expiresAt: new Date(Date.now() - 1000000)
  184. }
  185. }, cb
  186. (cb) =>
  187. @user.request {
  188. method: 'POST',
  189. url: '/user/emails/confirm',
  190. json:
  191. token: token
  192. }, (error, response, body) =>
  193. return done(error) if error?
  194. expect(response.statusCode).to.equal 404
  195. cb()
  196. ], done
  197. describe 'resending the confirmation', ->
  198. it 'should generate a new token', (done) ->
  199. async.series [
  200. (cb) =>
  201. @user.request {
  202. method: 'POST',
  203. url: '/user/emails',
  204. json:
  205. email: 'reconfirmation-email@example.com'
  206. }, (error, response, body) =>
  207. return done(error) if error?
  208. expect(response.statusCode).to.equal 204
  209. cb()
  210. (cb) =>
  211. db.tokens.find {
  212. use: 'email_confirmation',
  213. 'data.user_id': @user._id,
  214. usedAt: { $exists: false }
  215. }, (error, tokens) =>
  216. # There should only be one confirmation token at the moment
  217. expect(tokens.length).to.equal 1
  218. expect(tokens[0].data.email).to.equal 'reconfirmation-email@example.com'
  219. expect(tokens[0].data.user_id).to.equal @user._id
  220. cb()
  221. (cb) =>
  222. @user.request {
  223. method: 'POST',
  224. url: '/user/emails/resend_confirmation',
  225. json:
  226. email: 'reconfirmation-email@example.com'
  227. }, (error, response, body) =>
  228. return done(error) if error?
  229. expect(response.statusCode).to.equal 200
  230. cb()
  231. (cb) =>
  232. db.tokens.find {
  233. use: 'email_confirmation',
  234. 'data.user_id': @user._id,
  235. usedAt: { $exists: false }
  236. }, (error, tokens) =>
  237. # There should be two tokens now
  238. expect(tokens.length).to.equal 2
  239. expect(tokens[0].data.email).to.equal 'reconfirmation-email@example.com'
  240. expect(tokens[0].data.user_id).to.equal @user._id
  241. expect(tokens[1].data.email).to.equal 'reconfirmation-email@example.com'
  242. expect(tokens[1].data.user_id).to.equal @user._id
  243. cb()
  244. ], done
  245. it 'should create a new token if none exists', (done) ->
  246. # This should only be for users that have sign up with their main
  247. # emails before the confirmation system existed
  248. async.series [
  249. (cb) =>
  250. db.tokens.remove {
  251. use: 'email_confirmation',
  252. 'data.user_id': @user._id,
  253. usedAt: { $exists: false }
  254. }, cb
  255. (cb) =>
  256. @user.request {
  257. method: 'POST',
  258. url: '/user/emails/resend_confirmation',
  259. json:
  260. email: @user.email
  261. }, (error, response, body) =>
  262. return done(error) if error?
  263. expect(response.statusCode).to.equal 200
  264. cb()
  265. (cb) =>
  266. db.tokens.find {
  267. use: 'email_confirmation',
  268. 'data.user_id': @user._id,
  269. usedAt: { $exists: false }
  270. }, (error, tokens) =>
  271. # There should still only be one confirmation token
  272. expect(tokens.length).to.equal 1
  273. expect(tokens[0].data.email).to.equal @user.email
  274. expect(tokens[0].data.user_id).to.equal @user._id
  275. cb()
  276. ], done
  277. it "should not allow reconfirmation if the email doesn't match the user", (done) ->
  278. async.series [
  279. (cb) =>
  280. @user.request {
  281. method: 'POST',
  282. url: '/user/emails/resend_confirmation',
  283. json:
  284. email: 'non-matching-email@example.com'
  285. }, (error, response, body) =>
  286. return done(error) if error?
  287. expect(response.statusCode).to.equal 422
  288. cb()
  289. (cb) =>
  290. db.tokens.find {
  291. use: 'email_confirmation',
  292. 'data.user_id': @user._id,
  293. usedAt: { $exists: false }
  294. }, (error, tokens) =>
  295. expect(tokens.length).to.equal 0
  296. cb()
  297. ], done