LaunchpadControllerTests.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104
  1. /* eslint-disable
  2. max-len,
  3. no-return-assign,
  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. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  12. */
  13. const SandboxedModule = require('sandboxed-module')
  14. const assert = require('assert')
  15. const { expect } = require('chai')
  16. const sinon = require('sinon')
  17. const modulePath = require('path').join(
  18. __dirname,
  19. '../../../app/src/LaunchpadController.js'
  20. )
  21. describe('LaunchpadController', function () {
  22. beforeEach(function () {
  23. this.user = {
  24. _id: '323123',
  25. first_name: 'fn',
  26. last_name: 'ln',
  27. save: sinon.stub().callsArgWith(0),
  28. }
  29. this.User = {}
  30. this.LaunchpadController = SandboxedModule.require(modulePath, {
  31. requires: {
  32. '@overleaf/settings': (this.Settings = {
  33. adminPrivilegeAvailable: true,
  34. }),
  35. '@overleaf/metrics': (this.Metrics = {}),
  36. '../../../../app/src/Features/User/UserRegistrationHandler':
  37. (this.UserRegistrationHandler = {}),
  38. '../../../../app/src/Features/Email/EmailHandler': (this.EmailHandler =
  39. {}),
  40. '../../../../app/src/Features/User/UserGetter': (this.UserGetter = {}),
  41. '../../../../app/src/models/User': { User: this.User },
  42. '../../../../app/src/Features/Authentication/AuthenticationController':
  43. (this.AuthenticationController = {}),
  44. '../../../../app/src/Features/Authentication/AuthenticationManager':
  45. (this.AuthenticationManager = {}),
  46. '../../../../app/src/Features/Authentication/SessionManager':
  47. (this.SessionManager = {}),
  48. },
  49. })
  50. this.email = 'bob@smith.com'
  51. this.req = {
  52. query: {},
  53. body: {},
  54. session: {},
  55. }
  56. this.res = {
  57. render: sinon.stub(),
  58. redirect: sinon.stub(),
  59. json: sinon.stub(),
  60. send: sinon.stub(),
  61. sendStatus: sinon.stub(),
  62. locals: {
  63. translate(key) {
  64. return key
  65. },
  66. },
  67. }
  68. this.res.status = sinon.stub().returns(this.res)
  69. return (this.next = sinon.stub())
  70. })
  71. describe('launchpadPage', function () {
  72. beforeEach(function () {
  73. this._atLeastOneAdminExists = sinon.stub(
  74. this.LaunchpadController,
  75. '_atLeastOneAdminExists'
  76. )
  77. return (this.AuthenticationController.setRedirectInSession = sinon.stub())
  78. })
  79. afterEach(function () {
  80. return this._atLeastOneAdminExists.restore()
  81. })
  82. describe('when the user is not logged in', function () {
  83. beforeEach(function () {
  84. this.SessionManager.getSessionUser = sinon.stub().returns(null)
  85. return (this.res.render = sinon.stub())
  86. })
  87. describe('when there are no admins', function () {
  88. beforeEach(function () {
  89. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  90. return this.LaunchpadController.launchpadPage(
  91. this.req,
  92. this.res,
  93. this.next
  94. )
  95. })
  96. it('should render the launchpad page', function () {
  97. const viewPath = require('path').join(
  98. __dirname,
  99. '../../../app/views/launchpad'
  100. )
  101. this.res.render.callCount.should.equal(1)
  102. return this.res.render
  103. .calledWith(viewPath, {
  104. adminUserExists: false,
  105. authMethod: 'local',
  106. })
  107. .should.equal(true)
  108. })
  109. })
  110. describe('when there is at least one admin', function () {
  111. beforeEach(function () {
  112. this._atLeastOneAdminExists.callsArgWith(0, null, true)
  113. return this.LaunchpadController.launchpadPage(
  114. this.req,
  115. this.res,
  116. this.next
  117. )
  118. })
  119. it('should redirect to login page', function () {
  120. this.AuthenticationController.setRedirectInSession.callCount.should.equal(
  121. 1
  122. )
  123. this.res.redirect.calledWith('/login').should.equal(true)
  124. })
  125. it('should not render the launchpad page', function () {
  126. return this.res.render.callCount.should.equal(0)
  127. })
  128. })
  129. })
  130. describe('when the user is logged in', function () {
  131. beforeEach(function () {
  132. this.user = {
  133. _id: 'abcd',
  134. email: 'abcd@example.com',
  135. }
  136. this.SessionManager.getSessionUser = sinon.stub().returns(this.user)
  137. this._atLeastOneAdminExists.callsArgWith(0, null, true)
  138. this.res.render = sinon.stub()
  139. return (this.res.redirect = sinon.stub())
  140. })
  141. describe('when the user is an admin', function () {
  142. beforeEach(function () {
  143. this.UserGetter.getUser = sinon
  144. .stub()
  145. .callsArgWith(2, null, { isAdmin: true })
  146. return this.LaunchpadController.launchpadPage(
  147. this.req,
  148. this.res,
  149. this.next
  150. )
  151. })
  152. it('should render the launchpad page', function () {
  153. const viewPath = require('path').join(
  154. __dirname,
  155. '../../../app/views/launchpad'
  156. )
  157. this.res.render.callCount.should.equal(1)
  158. return this.res.render
  159. .calledWith(viewPath, {
  160. wsUrl: undefined,
  161. adminUserExists: true,
  162. authMethod: 'local',
  163. })
  164. .should.equal(true)
  165. })
  166. })
  167. describe('when the user is not an admin', function () {
  168. beforeEach(function () {
  169. this.UserGetter.getUser = sinon
  170. .stub()
  171. .callsArgWith(2, null, { isAdmin: false })
  172. return this.LaunchpadController.launchpadPage(
  173. this.req,
  174. this.res,
  175. this.next
  176. )
  177. })
  178. it('should redirect to restricted page', function () {
  179. this.res.redirect.callCount.should.equal(1)
  180. return this.res.redirect.calledWith('/restricted').should.equal(true)
  181. })
  182. })
  183. })
  184. })
  185. describe('_atLeastOneAdminExists', function () {
  186. describe('when there are no admins', function () {
  187. beforeEach(function () {
  188. return (this.UserGetter.getUser = sinon
  189. .stub()
  190. .callsArgWith(2, null, null))
  191. })
  192. it('should callback with false', function (done) {
  193. return this.LaunchpadController._atLeastOneAdminExists(
  194. (err, exists) => {
  195. expect(err).to.equal(null)
  196. expect(exists).to.equal(false)
  197. return done()
  198. }
  199. )
  200. })
  201. })
  202. describe('when there are some admins', function () {
  203. beforeEach(function () {
  204. return (this.UserGetter.getUser = sinon
  205. .stub()
  206. .callsArgWith(2, null, { _id: 'abcd' }))
  207. })
  208. it('should callback with true', function (done) {
  209. return this.LaunchpadController._atLeastOneAdminExists(
  210. (err, exists) => {
  211. expect(err).to.equal(null)
  212. expect(exists).to.equal(true)
  213. return done()
  214. }
  215. )
  216. })
  217. })
  218. describe('when getUser produces an error', function () {
  219. beforeEach(function () {
  220. return (this.UserGetter.getUser = sinon
  221. .stub()
  222. .callsArgWith(2, new Error('woops')))
  223. })
  224. it('should produce an error', function (done) {
  225. return this.LaunchpadController._atLeastOneAdminExists(
  226. (err, exists) => {
  227. expect(err).to.not.equal(null)
  228. expect(err).to.be.instanceof(Error)
  229. expect(exists).to.equal(undefined)
  230. return done()
  231. }
  232. )
  233. })
  234. })
  235. })
  236. describe('sendTestEmail', function () {
  237. beforeEach(function () {
  238. this.EmailHandler.sendEmail = sinon.stub().callsArgWith(2, null)
  239. this.req.body.email = 'someone@example.com'
  240. this.res.sendStatus = sinon.stub()
  241. return (this.next = sinon.stub())
  242. })
  243. it('should produce a 200 response', function () {
  244. this.LaunchpadController.sendTestEmail(this.req, this.res, this.next)
  245. this.res.json
  246. .calledWith({
  247. message: 'email_sent',
  248. })
  249. .should.equal(true)
  250. })
  251. it('should not call next with an error', function () {
  252. this.LaunchpadController.sendTestEmail(this.req, this.res, this.next)
  253. return this.next.callCount.should.equal(0)
  254. })
  255. it('should have called sendEmail', function () {
  256. this.LaunchpadController.sendTestEmail(this.req, this.res, this.next)
  257. this.EmailHandler.sendEmail.callCount.should.equal(1)
  258. return this.EmailHandler.sendEmail
  259. .calledWith('testEmail')
  260. .should.equal(true)
  261. })
  262. describe('when sendEmail produces an error', function () {
  263. beforeEach(function () {
  264. return (this.EmailHandler.sendEmail = sinon
  265. .stub()
  266. .callsArgWith(2, new Error('woops')))
  267. })
  268. it('should call next with an error', function () {
  269. this.LaunchpadController.sendTestEmail(this.req, this.res, this.next)
  270. this.next.callCount.should.equal(1)
  271. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  272. })
  273. })
  274. describe('when no email address is supplied', function () {
  275. beforeEach(function () {
  276. return (this.req.body.email = undefined)
  277. })
  278. it('should produce a 400 response', function () {
  279. this.LaunchpadController.sendTestEmail(this.req, this.res, this.next)
  280. this.res.status.calledWith(400).should.equal(true)
  281. this.res.json
  282. .calledWith({
  283. message: 'no email address supplied',
  284. })
  285. .should.equal(true)
  286. })
  287. })
  288. })
  289. describe('registerAdmin', function () {
  290. beforeEach(function () {
  291. return (this._atLeastOneAdminExists = sinon.stub(
  292. this.LaunchpadController,
  293. '_atLeastOneAdminExists'
  294. ))
  295. })
  296. afterEach(function () {
  297. return this._atLeastOneAdminExists.restore()
  298. })
  299. describe('when all goes well', function () {
  300. beforeEach(function () {
  301. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  302. this.email = 'someone@example.com'
  303. this.password = 'a_really_bad_password'
  304. this.req.body.email = this.email
  305. this.req.body.password = this.password
  306. this.user = {
  307. _id: 'abcdef',
  308. email: this.email,
  309. }
  310. this.UserRegistrationHandler.registerNewUser = sinon
  311. .stub()
  312. .callsArgWith(1, null, this.user)
  313. this.User.updateOne = sinon.stub().callsArgWith(2, null)
  314. this.AuthenticationController.setRedirectInSession = sinon.stub()
  315. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  316. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  317. this.res.json = sinon.stub()
  318. this.next = sinon.stub()
  319. return this.LaunchpadController.registerAdmin(
  320. this.req,
  321. this.res,
  322. this.next
  323. )
  324. })
  325. it('should send back a json response', function () {
  326. this.res.json.callCount.should.equal(1)
  327. expect(this.res.json).to.have.been.calledWith({ redir: '/launchpad' })
  328. })
  329. it('should have checked for existing admins', function () {
  330. return this._atLeastOneAdminExists.callCount.should.equal(1)
  331. })
  332. it('should have called registerNewUser', function () {
  333. this.UserRegistrationHandler.registerNewUser.callCount.should.equal(1)
  334. return this.UserRegistrationHandler.registerNewUser
  335. .calledWith({ email: this.email, password: this.password })
  336. .should.equal(true)
  337. })
  338. it('should have updated the user to make them an admin', function () {
  339. this.User.updateOne.callCount.should.equal(1)
  340. return this.User.updateOne
  341. .calledWithMatch(
  342. { _id: this.user._id },
  343. {
  344. $set: {
  345. isAdmin: true,
  346. emails: [{ email: this.user.email }],
  347. },
  348. }
  349. )
  350. .should.equal(true)
  351. })
  352. })
  353. describe('when no email is supplied', function () {
  354. beforeEach(function () {
  355. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  356. this.email = undefined
  357. this.password = 'a_really_bad_password'
  358. this.req.body.email = this.email
  359. this.req.body.password = this.password
  360. this.user = {
  361. _id: 'abcdef',
  362. email: this.email,
  363. }
  364. this.UserRegistrationHandler.registerNewUser = sinon.stub()
  365. this.User.updateOne = sinon.stub()
  366. this.AuthenticationController.setRedirectInSession = sinon.stub()
  367. this.res.sendStatus = sinon.stub()
  368. this.next = sinon.stub()
  369. return this.LaunchpadController.registerAdmin(
  370. this.req,
  371. this.res,
  372. this.next
  373. )
  374. })
  375. it('should send a 400 response', function () {
  376. this.res.sendStatus.callCount.should.equal(1)
  377. return this.res.sendStatus.calledWith(400).should.equal(true)
  378. })
  379. it('should not check for existing admins', function () {
  380. return this._atLeastOneAdminExists.callCount.should.equal(0)
  381. })
  382. it('should not call registerNewUser', function () {
  383. return this.UserRegistrationHandler.registerNewUser.callCount.should.equal(
  384. 0
  385. )
  386. })
  387. })
  388. describe('when no password is supplied', function () {
  389. beforeEach(function () {
  390. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  391. this.email = 'someone@example.com'
  392. this.password = undefined
  393. this.req.body.email = this.email
  394. this.req.body.password = this.password
  395. this.user = {
  396. _id: 'abcdef',
  397. email: this.email,
  398. }
  399. this.UserRegistrationHandler.registerNewUser = sinon.stub()
  400. this.User.updateOne = sinon.stub()
  401. this.AuthenticationController.setRedirectInSession = sinon.stub()
  402. this.res.sendStatus = sinon.stub()
  403. this.next = sinon.stub()
  404. return this.LaunchpadController.registerAdmin(
  405. this.req,
  406. this.res,
  407. this.next
  408. )
  409. })
  410. it('should send a 400 response', function () {
  411. this.res.sendStatus.callCount.should.equal(1)
  412. return this.res.sendStatus.calledWith(400).should.equal(true)
  413. })
  414. it('should not check for existing admins', function () {
  415. return this._atLeastOneAdminExists.callCount.should.equal(0)
  416. })
  417. it('should not call registerNewUser', function () {
  418. return this.UserRegistrationHandler.registerNewUser.callCount.should.equal(
  419. 0
  420. )
  421. })
  422. })
  423. describe('when an invalid email is supplied', function () {
  424. beforeEach(function () {
  425. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  426. this.email = 'someone@example.com'
  427. this.password = 'invalid password'
  428. this.req.body.email = this.email
  429. this.req.body.password = this.password
  430. this.user = {
  431. _id: 'abcdef',
  432. email: this.email,
  433. }
  434. this.UserRegistrationHandler.registerNewUser = sinon.stub()
  435. this.User.updateOne = sinon.stub()
  436. this.AuthenticationController.setRedirectInSession = sinon.stub()
  437. this.AuthenticationManager.validateEmail = sinon
  438. .stub()
  439. .returns(new Error('bad email'))
  440. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  441. this.res.sendStatus = sinon.stub()
  442. this.next = sinon.stub()
  443. return this.LaunchpadController.registerAdmin(
  444. this.req,
  445. this.res,
  446. this.next
  447. )
  448. })
  449. it('should send a 400 response', function () {
  450. this.res.status.callCount.should.equal(1)
  451. this.res.status.calledWith(400).should.equal(true)
  452. return this.res.json.calledWith({
  453. message: { type: 'error', text: 'bad email' },
  454. })
  455. })
  456. it('should not call registerNewUser', function () {
  457. return this.UserRegistrationHandler.registerNewUser.callCount.should.equal(
  458. 0
  459. )
  460. })
  461. })
  462. describe('when an invalid password is supplied', function () {
  463. beforeEach(function () {
  464. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  465. this.email = 'someone@example.com'
  466. this.password = 'invalid password'
  467. this.req.body.email = this.email
  468. this.req.body.password = this.password
  469. this.user = {
  470. _id: 'abcdef',
  471. email: this.email,
  472. }
  473. this.UserRegistrationHandler.registerNewUser = sinon.stub()
  474. this.User.updateOne = sinon.stub()
  475. this.AuthenticationController.setRedirectInSession = sinon.stub()
  476. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  477. this.AuthenticationManager.validatePassword = sinon
  478. .stub()
  479. .returns(new Error('bad password'))
  480. this.res.sendStatus = sinon.stub()
  481. this.next = sinon.stub()
  482. return this.LaunchpadController.registerAdmin(
  483. this.req,
  484. this.res,
  485. this.next
  486. )
  487. })
  488. it('should send a 400 response', function () {
  489. this.res.status.callCount.should.equal(1)
  490. this.res.status.calledWith(400).should.equal(true)
  491. return this.res.json.calledWith({
  492. message: { type: 'error', text: 'bad password' },
  493. })
  494. })
  495. it('should not call registerNewUser', function () {
  496. return this.UserRegistrationHandler.registerNewUser.callCount.should.equal(
  497. 0
  498. )
  499. })
  500. })
  501. describe('when there are already existing admins', function () {
  502. beforeEach(function () {
  503. this._atLeastOneAdminExists.callsArgWith(0, null, true)
  504. this.email = 'someone@example.com'
  505. this.password = 'a_really_bad_password'
  506. this.req.body.email = this.email
  507. this.req.body.password = this.password
  508. this.user = {
  509. _id: 'abcdef',
  510. email: this.email,
  511. }
  512. this.UserRegistrationHandler.registerNewUser = sinon.stub()
  513. this.User.updateOne = sinon.stub()
  514. this.AuthenticationController.setRedirectInSession = sinon.stub()
  515. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  516. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  517. this.res.sendStatus = sinon.stub()
  518. this.next = sinon.stub()
  519. return this.LaunchpadController.registerAdmin(
  520. this.req,
  521. this.res,
  522. this.next
  523. )
  524. })
  525. it('should send a 403 response', function () {
  526. this.res.status.callCount.should.equal(1)
  527. return this.res.status.calledWith(403).should.equal(true)
  528. })
  529. it('should not call registerNewUser', function () {
  530. return this.UserRegistrationHandler.registerNewUser.callCount.should.equal(
  531. 0
  532. )
  533. })
  534. })
  535. describe('when checking admins produces an error', function () {
  536. beforeEach(function () {
  537. this._atLeastOneAdminExists.callsArgWith(0, new Error('woops'))
  538. this.email = 'someone@example.com'
  539. this.password = 'a_really_bad_password'
  540. this.req.body.email = this.email
  541. this.req.body.password = this.password
  542. this.user = {
  543. _id: 'abcdef',
  544. email: this.email,
  545. }
  546. this.UserRegistrationHandler.registerNewUser = sinon.stub()
  547. this.User.updateOne = sinon.stub()
  548. this.AuthenticationController.setRedirectInSession = sinon.stub()
  549. this.res.sendStatus = sinon.stub()
  550. this.next = sinon.stub()
  551. return this.LaunchpadController.registerAdmin(
  552. this.req,
  553. this.res,
  554. this.next
  555. )
  556. })
  557. it('should call next with an error', function () {
  558. this.next.callCount.should.equal(1)
  559. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  560. })
  561. it('should have checked for existing admins', function () {
  562. return this._atLeastOneAdminExists.callCount.should.equal(1)
  563. })
  564. it('should not call registerNewUser', function () {
  565. return this.UserRegistrationHandler.registerNewUser.callCount.should.equal(
  566. 0
  567. )
  568. })
  569. })
  570. describe('when registerNewUser produces an error', function () {
  571. beforeEach(function () {
  572. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  573. this.email = 'someone@example.com'
  574. this.password = 'a_really_bad_password'
  575. this.req.body.email = this.email
  576. this.req.body.password = this.password
  577. this.user = {
  578. _id: 'abcdef',
  579. email: this.email,
  580. }
  581. this.UserRegistrationHandler.registerNewUser = sinon
  582. .stub()
  583. .callsArgWith(1, new Error('woops'))
  584. this.User.updateOne = sinon.stub()
  585. this.AuthenticationController.setRedirectInSession = sinon.stub()
  586. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  587. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  588. this.res.json = sinon.stub()
  589. this.next = sinon.stub()
  590. return this.LaunchpadController.registerAdmin(
  591. this.req,
  592. this.res,
  593. this.next
  594. )
  595. })
  596. it('should call next with an error', function () {
  597. this.next.callCount.should.equal(1)
  598. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  599. })
  600. it('should have checked for existing admins', function () {
  601. return this._atLeastOneAdminExists.callCount.should.equal(1)
  602. })
  603. it('should have called registerNewUser', function () {
  604. this.UserRegistrationHandler.registerNewUser.callCount.should.equal(1)
  605. return this.UserRegistrationHandler.registerNewUser
  606. .calledWith({ email: this.email, password: this.password })
  607. .should.equal(true)
  608. })
  609. it('should not call update', function () {
  610. return this.User.updateOne.callCount.should.equal(0)
  611. })
  612. })
  613. describe('when user update produces an error', function () {
  614. beforeEach(function () {
  615. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  616. this.email = 'someone@example.com'
  617. this.password = 'a_really_bad_password'
  618. this.req.body.email = this.email
  619. this.req.body.password = this.password
  620. this.user = {
  621. _id: 'abcdef',
  622. email: this.email,
  623. }
  624. this.UserRegistrationHandler.registerNewUser = sinon
  625. .stub()
  626. .callsArgWith(1, null, this.user)
  627. this.User.updateOne = sinon.stub().callsArgWith(2, new Error('woops'))
  628. this.AuthenticationController.setRedirectInSession = sinon.stub()
  629. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  630. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  631. this.res.json = sinon.stub()
  632. this.next = sinon.stub()
  633. return this.LaunchpadController.registerAdmin(
  634. this.req,
  635. this.res,
  636. this.next
  637. )
  638. })
  639. it('should call next with an error', function () {
  640. this.next.callCount.should.equal(1)
  641. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  642. })
  643. it('should have checked for existing admins', function () {
  644. return this._atLeastOneAdminExists.callCount.should.equal(1)
  645. })
  646. it('should have called registerNewUser', function () {
  647. this.UserRegistrationHandler.registerNewUser.callCount.should.equal(1)
  648. return this.UserRegistrationHandler.registerNewUser
  649. .calledWith({ email: this.email, password: this.password })
  650. .should.equal(true)
  651. })
  652. })
  653. describe('when overleaf', function () {
  654. beforeEach(function () {
  655. this.Settings.overleaf = { one: 1 }
  656. this.Settings.createV1AccountOnLogin = true
  657. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  658. this.email = 'someone@example.com'
  659. this.password = 'a_really_bad_password'
  660. this.req.body.email = this.email
  661. this.req.body.password = this.password
  662. this.user = {
  663. _id: 'abcdef',
  664. email: this.email,
  665. }
  666. this.UserRegistrationHandler.registerNewUser = sinon
  667. .stub()
  668. .callsArgWith(1, null, this.user)
  669. this.User.updateOne = sinon.stub().callsArgWith(2, null)
  670. this.AuthenticationController.setRedirectInSession = sinon.stub()
  671. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  672. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  673. this.UserGetter.getUser = sinon
  674. .stub()
  675. .callsArgWith(1, null, { _id: '1234' })
  676. this.res.json = sinon.stub()
  677. this.next = sinon.stub()
  678. return this.LaunchpadController.registerAdmin(
  679. this.req,
  680. this.res,
  681. this.next
  682. )
  683. })
  684. it('should send back a json response', function () {
  685. this.res.json.callCount.should.equal(1)
  686. expect(this.res.json).to.have.been.calledWith({ redir: '/launchpad' })
  687. })
  688. it('should have checked for existing admins', function () {
  689. return this._atLeastOneAdminExists.callCount.should.equal(1)
  690. })
  691. it('should have called registerNewUser', function () {
  692. this.UserRegistrationHandler.registerNewUser.callCount.should.equal(1)
  693. return this.UserRegistrationHandler.registerNewUser
  694. .calledWith({ email: this.email, password: this.password })
  695. .should.equal(true)
  696. })
  697. it('should have updated the user to make them an admin', function () {
  698. return this.User.updateOne
  699. .calledWith(
  700. { _id: this.user._id },
  701. {
  702. $set: {
  703. isAdmin: true,
  704. emails: [{ email: this.user.email }],
  705. },
  706. }
  707. )
  708. .should.equal(true)
  709. })
  710. })
  711. })
  712. describe('registerExternalAuthAdmin', function () {
  713. beforeEach(function () {
  714. this.Settings.ldap = { one: 1 }
  715. return (this._atLeastOneAdminExists = sinon.stub(
  716. this.LaunchpadController,
  717. '_atLeastOneAdminExists'
  718. ))
  719. })
  720. afterEach(function () {
  721. return this._atLeastOneAdminExists.restore()
  722. })
  723. describe('when all goes well', function () {
  724. beforeEach(function () {
  725. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  726. this.email = 'someone@example.com'
  727. this.req.body.email = this.email
  728. this.user = {
  729. _id: 'abcdef',
  730. email: this.email,
  731. }
  732. this.UserRegistrationHandler.registerNewUser = sinon
  733. .stub()
  734. .callsArgWith(1, null, this.user)
  735. this.User.updateOne = sinon.stub().callsArgWith(2, null)
  736. this.AuthenticationController.setRedirectInSession = sinon.stub()
  737. this.res.json = sinon.stub()
  738. this.next = sinon.stub()
  739. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  740. this.req,
  741. this.res,
  742. this.next
  743. )
  744. })
  745. it('should send back a json response', function () {
  746. this.res.json.callCount.should.equal(1)
  747. return expect(this.res.json.lastCall.args[0].email).to.equal(this.email)
  748. })
  749. it('should have checked for existing admins', function () {
  750. return this._atLeastOneAdminExists.callCount.should.equal(1)
  751. })
  752. it('should have called registerNewUser', function () {
  753. this.UserRegistrationHandler.registerNewUser.callCount.should.equal(1)
  754. return this.UserRegistrationHandler.registerNewUser
  755. .calledWith({
  756. email: this.email,
  757. password: 'password_here',
  758. first_name: this.email,
  759. last_name: '',
  760. })
  761. .should.equal(true)
  762. })
  763. it('should have updated the user to make them an admin', function () {
  764. this.User.updateOne.callCount.should.equal(1)
  765. return this.User.updateOne
  766. .calledWith(
  767. { _id: this.user._id },
  768. {
  769. $set: { isAdmin: true },
  770. emails: [{ email: this.user.email }],
  771. }
  772. )
  773. .should.equal(true)
  774. })
  775. it('should have set a redirect in session', function () {
  776. this.AuthenticationController.setRedirectInSession.callCount.should.equal(
  777. 1
  778. )
  779. return this.AuthenticationController.setRedirectInSession
  780. .calledWith(this.req, '/launchpad')
  781. .should.equal(true)
  782. })
  783. })
  784. describe('when the authMethod is invalid', function () {
  785. beforeEach(function () {
  786. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  787. this.email = undefined
  788. this.req.body.email = this.email
  789. this.user = {
  790. _id: 'abcdef',
  791. email: this.email,
  792. }
  793. this.UserRegistrationHandler.registerNewUser = sinon.stub()
  794. this.User.updateOne = sinon.stub()
  795. this.AuthenticationController.setRedirectInSession = sinon.stub()
  796. this.res.sendStatus = sinon.stub()
  797. this.next = sinon.stub()
  798. return this.LaunchpadController.registerExternalAuthAdmin(
  799. 'NOTAVALIDAUTHMETHOD'
  800. )(this.req, this.res, this.next)
  801. })
  802. it('should send a 403 response', function () {
  803. this.res.sendStatus.callCount.should.equal(1)
  804. return this.res.sendStatus.calledWith(403).should.equal(true)
  805. })
  806. it('should not check for existing admins', function () {
  807. return this._atLeastOneAdminExists.callCount.should.equal(0)
  808. })
  809. it('should not call registerNewUser', function () {
  810. return this.UserRegistrationHandler.registerNewUser.callCount.should.equal(
  811. 0
  812. )
  813. })
  814. })
  815. describe('when no email is supplied', function () {
  816. beforeEach(function () {
  817. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  818. this.email = undefined
  819. this.req.body.email = this.email
  820. this.user = {
  821. _id: 'abcdef',
  822. email: this.email,
  823. }
  824. this.UserRegistrationHandler.registerNewUser = sinon.stub()
  825. this.User.updateOne = sinon.stub()
  826. this.AuthenticationController.setRedirectInSession = sinon.stub()
  827. this.res.sendStatus = sinon.stub()
  828. this.next = sinon.stub()
  829. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  830. this.req,
  831. this.res,
  832. this.next
  833. )
  834. })
  835. it('should send a 400 response', function () {
  836. this.res.sendStatus.callCount.should.equal(1)
  837. return this.res.sendStatus.calledWith(400).should.equal(true)
  838. })
  839. it('should not check for existing admins', function () {
  840. return this._atLeastOneAdminExists.callCount.should.equal(0)
  841. })
  842. it('should not call registerNewUser', function () {
  843. return this.UserRegistrationHandler.registerNewUser.callCount.should.equal(
  844. 0
  845. )
  846. })
  847. })
  848. describe('when there are already existing admins', function () {
  849. beforeEach(function () {
  850. this._atLeastOneAdminExists.callsArgWith(0, null, true)
  851. this.email = 'someone@example.com'
  852. this.req.body.email = this.email
  853. this.user = {
  854. _id: 'abcdef',
  855. email: this.email,
  856. }
  857. this.UserRegistrationHandler.registerNewUser = sinon.stub()
  858. this.User.updateOne = sinon.stub()
  859. this.AuthenticationController.setRedirectInSession = sinon.stub()
  860. this.res.sendStatus = sinon.stub()
  861. this.next = sinon.stub()
  862. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  863. this.req,
  864. this.res,
  865. this.next
  866. )
  867. })
  868. it('should send a 403 response', function () {
  869. this.res.sendStatus.callCount.should.equal(1)
  870. return this.res.sendStatus.calledWith(403).should.equal(true)
  871. })
  872. it('should not call registerNewUser', function () {
  873. return this.UserRegistrationHandler.registerNewUser.callCount.should.equal(
  874. 0
  875. )
  876. })
  877. })
  878. describe('when checking admins produces an error', function () {
  879. beforeEach(function () {
  880. this._atLeastOneAdminExists.callsArgWith(0, new Error('woops'))
  881. this.email = 'someone@example.com'
  882. this.req.body.email = this.email
  883. this.user = {
  884. _id: 'abcdef',
  885. email: this.email,
  886. }
  887. this.UserRegistrationHandler.registerNewUser = sinon.stub()
  888. this.User.updateOne = sinon.stub()
  889. this.AuthenticationController.setRedirectInSession = sinon.stub()
  890. this.res.sendStatus = sinon.stub()
  891. this.next = sinon.stub()
  892. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  893. this.req,
  894. this.res,
  895. this.next
  896. )
  897. })
  898. it('should call next with an error', function () {
  899. this.next.callCount.should.equal(1)
  900. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  901. })
  902. it('should have checked for existing admins', function () {
  903. return this._atLeastOneAdminExists.callCount.should.equal(1)
  904. })
  905. it('should not call registerNewUser', function () {
  906. return this.UserRegistrationHandler.registerNewUser.callCount.should.equal(
  907. 0
  908. )
  909. })
  910. })
  911. describe('when registerNewUser produces an error', function () {
  912. beforeEach(function () {
  913. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  914. this.email = 'someone@example.com'
  915. this.req.body.email = this.email
  916. this.user = {
  917. _id: 'abcdef',
  918. email: this.email,
  919. }
  920. this.UserRegistrationHandler.registerNewUser = sinon
  921. .stub()
  922. .callsArgWith(1, new Error('woops'))
  923. this.User.updateOne = sinon.stub()
  924. this.AuthenticationController.setRedirectInSession = sinon.stub()
  925. this.res.json = sinon.stub()
  926. this.next = sinon.stub()
  927. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  928. this.req,
  929. this.res,
  930. this.next
  931. )
  932. })
  933. it('should call next with an error', function () {
  934. this.next.callCount.should.equal(1)
  935. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  936. })
  937. it('should have checked for existing admins', function () {
  938. return this._atLeastOneAdminExists.callCount.should.equal(1)
  939. })
  940. it('should have called registerNewUser', function () {
  941. this.UserRegistrationHandler.registerNewUser.callCount.should.equal(1)
  942. return this.UserRegistrationHandler.registerNewUser
  943. .calledWith({
  944. email: this.email,
  945. password: 'password_here',
  946. first_name: this.email,
  947. last_name: '',
  948. })
  949. .should.equal(true)
  950. })
  951. it('should not call update', function () {
  952. return this.User.updateOne.callCount.should.equal(0)
  953. })
  954. })
  955. describe('when user update produces an error', function () {
  956. beforeEach(function () {
  957. this._atLeastOneAdminExists.callsArgWith(0, null, false)
  958. this.email = 'someone@example.com'
  959. this.req.body.email = this.email
  960. this.user = {
  961. _id: 'abcdef',
  962. email: this.email,
  963. }
  964. this.UserRegistrationHandler.registerNewUser = sinon
  965. .stub()
  966. .callsArgWith(1, null, this.user)
  967. this.User.updateOne = sinon.stub().callsArgWith(2, new Error('woops'))
  968. this.AuthenticationController.setRedirectInSession = sinon.stub()
  969. this.res.json = sinon.stub()
  970. this.next = sinon.stub()
  971. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  972. this.req,
  973. this.res,
  974. this.next
  975. )
  976. })
  977. it('should call next with an error', function () {
  978. this.next.callCount.should.equal(1)
  979. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  980. })
  981. it('should have checked for existing admins', function () {
  982. return this._atLeastOneAdminExists.callCount.should.equal(1)
  983. })
  984. it('should have called registerNewUser', function () {
  985. this.UserRegistrationHandler.registerNewUser.callCount.should.equal(1)
  986. return this.UserRegistrationHandler.registerNewUser
  987. .calledWith({
  988. email: this.email,
  989. password: 'password_here',
  990. first_name: this.email,
  991. last_name: '',
  992. })
  993. .should.equal(true)
  994. })
  995. })
  996. })
  997. })