SudoModeControllerTests.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  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 sinon = require('sinon')
  15. const should = require('chai').should()
  16. const { expect } = require('chai')
  17. const MockRequest = require('../helpers/MockRequest')
  18. const MockResponse = require('../helpers/MockResponse')
  19. const modulePath = '../../../../app/src/Features/SudoMode/SudoModeController'
  20. describe('SudoModeController', function() {
  21. beforeEach(function() {
  22. this.user = {
  23. _id: 'abcd',
  24. email: 'user@example.com'
  25. }
  26. this.UserGetter = { getUser: sinon.stub().callsArgWith(2, null, this.user) }
  27. this.SudoModeHandler = {
  28. authenticate: sinon.stub(),
  29. isSudoModeActive: sinon.stub(),
  30. activateSudoMode: sinon.stub()
  31. }
  32. this.AuthenticationController = {
  33. getLoggedInUserId: sinon.stub().returns(this.user._id),
  34. _getRediretFromSession: sinon.stub()
  35. }
  36. this.UserGetter = { getUser: sinon.stub() }
  37. return (this.SudoModeController = SandboxedModule.require(modulePath, {
  38. globals: {
  39. console: console
  40. },
  41. requires: {
  42. 'logger-sharelatex': {
  43. log: sinon.stub(),
  44. warn: sinon.stub(),
  45. err: sinon.stub()
  46. },
  47. './SudoModeHandler': this.SudoModeHandler,
  48. '../Authentication/AuthenticationController': this
  49. .AuthenticationController,
  50. mongodb: {
  51. ObjectId() {
  52. return 'some_object_id'
  53. }
  54. },
  55. '../User/UserGetter': this.UserGetter,
  56. 'settings-sharelatex': (this.Settings = {})
  57. }
  58. }))
  59. })
  60. describe('sudoModePrompt', function() {
  61. beforeEach(function() {
  62. this.SudoModeHandler.isSudoModeActive = sinon
  63. .stub()
  64. .callsArgWith(1, null, false)
  65. this.req = {
  66. externalAuthenticationSystemUsed: sinon.stub().returns(false)
  67. }
  68. this.res = { redirect: sinon.stub(), render: sinon.stub() }
  69. return (this.next = sinon.stub())
  70. })
  71. it('should get the logged in user id', function() {
  72. this.SudoModeController.sudoModePrompt(this.req, this.res, this.next)
  73. this.AuthenticationController.getLoggedInUserId.callCount.should.equal(1)
  74. return this.AuthenticationController.getLoggedInUserId
  75. .calledWith(this.req)
  76. .should.equal(true)
  77. })
  78. it('should check if sudo-mode is active', function() {
  79. this.SudoModeController.sudoModePrompt(this.req, this.res, this.next)
  80. this.SudoModeHandler.isSudoModeActive.callCount.should.equal(1)
  81. return this.SudoModeHandler.isSudoModeActive
  82. .calledWith(this.user._id)
  83. .should.equal(true)
  84. })
  85. it('should redirect when sudo-mode is active', function() {
  86. this.SudoModeHandler.isSudoModeActive = sinon
  87. .stub()
  88. .callsArgWith(1, null, true)
  89. this.SudoModeController.sudoModePrompt(this.req, this.res, this.next)
  90. this.res.redirect.callCount.should.equal(1)
  91. return this.res.redirect.calledWith('/project').should.equal(true)
  92. })
  93. it('should render the sudo_mode_prompt page when sudo mode is not active', function() {
  94. this.SudoModeHandler.isSudoModeActive = sinon
  95. .stub()
  96. .callsArgWith(1, null, false)
  97. this.SudoModeController.sudoModePrompt(this.req, this.res, this.next)
  98. this.res.render.callCount.should.equal(1)
  99. return this.res.render
  100. .calledWith('sudo_mode/sudo_mode_prompt')
  101. .should.equal(true)
  102. })
  103. describe('when isSudoModeActive produces an error', function() {
  104. beforeEach(function() {
  105. this.SudoModeHandler.isSudoModeActive = sinon
  106. .stub()
  107. .callsArgWith(1, new Error('woops'))
  108. return (this.next = sinon.stub())
  109. })
  110. it('should call next with an error', function() {
  111. this.SudoModeController.sudoModePrompt(this.req, this.res, this.next)
  112. this.next.callCount.should.equal(1)
  113. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  114. })
  115. it('should not render page', function() {
  116. this.SudoModeController.sudoModePrompt(this.req, this.res, this.next)
  117. return this.res.render.callCount.should.equal(0)
  118. })
  119. })
  120. describe('when external auth system is used', function() {
  121. beforeEach(function() {
  122. return (this.req.externalAuthenticationSystemUsed = sinon
  123. .stub()
  124. .returns(true))
  125. })
  126. it('should redirect', function() {
  127. this.SudoModeController.sudoModePrompt(this.req, this.res, this.next)
  128. this.res.redirect.callCount.should.equal(1)
  129. return this.res.redirect.calledWith('/project').should.equal(true)
  130. })
  131. it('should not check if sudo mode is active', function() {
  132. this.SudoModeController.sudoModePrompt(this.req, this.res, this.next)
  133. return this.SudoModeHandler.isSudoModeActive.callCount.should.equal(0)
  134. })
  135. it('should not render page', function() {
  136. this.SudoModeController.sudoModePrompt(this.req, this.res, this.next)
  137. return this.res.render.callCount.should.equal(0)
  138. })
  139. })
  140. })
  141. describe('submitPassword', function() {
  142. beforeEach(function() {
  143. this.AuthenticationController._getRedirectFromSession = sinon
  144. .stub()
  145. .returns('/somewhere')
  146. this.UserGetter.getUser = sinon.stub().callsArgWith(2, null, this.user)
  147. this.SudoModeHandler.authenticate = sinon
  148. .stub()
  149. .callsArgWith(2, null, this.user)
  150. this.SudoModeHandler.activateSudoMode = sinon.stub().callsArgWith(1, null)
  151. this.password = 'a_terrible_secret'
  152. this.req = { body: { password: this.password } }
  153. this.res = { json: sinon.stub() }
  154. return (this.next = sinon.stub())
  155. })
  156. describe('when all goes well', function() {
  157. beforeEach(function() {})
  158. it('should get the logged in user id', function() {
  159. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  160. this.AuthenticationController.getLoggedInUserId.callCount.should.equal(
  161. 1
  162. )
  163. return this.AuthenticationController.getLoggedInUserId
  164. .calledWith(this.req)
  165. .should.equal(true)
  166. })
  167. it('should get redirect from session', function() {
  168. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  169. this.AuthenticationController._getRedirectFromSession.callCount.should.equal(
  170. 1
  171. )
  172. return this.AuthenticationController._getRedirectFromSession
  173. .calledWith(this.req)
  174. .should.equal(true)
  175. })
  176. it('should get the user from storage', function() {
  177. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  178. this.UserGetter.getUser.callCount.should.equal(1)
  179. return this.UserGetter.getUser
  180. .calledWith('some_object_id', { email: 1 })
  181. .should.equal(true)
  182. })
  183. it('should try to authenticate the user with the password', function() {
  184. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  185. this.SudoModeHandler.authenticate.callCount.should.equal(1)
  186. return this.SudoModeHandler.authenticate
  187. .calledWith(this.user.email, this.password)
  188. .should.equal(true)
  189. })
  190. it('should activate sudo mode', function() {
  191. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  192. this.SudoModeHandler.activateSudoMode.callCount.should.equal(1)
  193. return this.SudoModeHandler.activateSudoMode
  194. .calledWith(this.user._id)
  195. .should.equal(true)
  196. })
  197. it('should send back a json response', function() {
  198. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  199. this.res.json.callCount.should.equal(1)
  200. return this.res.json
  201. .calledWith({ redir: '/somewhere' })
  202. .should.equal(true)
  203. })
  204. it('should not call next', function() {
  205. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  206. return this.next.callCount.should.equal(0)
  207. })
  208. describe('when no password is supplied', function() {
  209. beforeEach(function() {
  210. this.req.body.password = ''
  211. return (this.next = sinon.stub())
  212. })
  213. it('should return next with an error', function() {
  214. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  215. this.next.callCount.should.equal(1)
  216. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  217. })
  218. it('should not get the user from storage', function() {
  219. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  220. return this.UserGetter.getUser.callCount.should.equal(0)
  221. })
  222. it('should not try to authenticate the user with the password', function() {
  223. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  224. return this.SudoModeHandler.authenticate.callCount.should.equal(0)
  225. })
  226. it('should not activate sudo mode', function() {
  227. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  228. return this.SudoModeHandler.activateSudoMode.callCount.should.equal(0)
  229. })
  230. it('should not send back a json response', function() {
  231. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  232. return this.res.json.callCount.should.equal(0)
  233. })
  234. })
  235. describe('when getUser produces an error', function() {
  236. beforeEach(function() {
  237. this.UserGetter.getUser = sinon
  238. .stub()
  239. .callsArgWith(2, new Error('woops'))
  240. return (this.next = sinon.stub())
  241. })
  242. it('should return next with an error', function() {
  243. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  244. this.next.callCount.should.equal(1)
  245. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  246. })
  247. it('should get the user from storage', function() {
  248. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  249. this.UserGetter.getUser.callCount.should.equal(1)
  250. return this.UserGetter.getUser
  251. .calledWith('some_object_id', { email: 1 })
  252. .should.equal(true)
  253. })
  254. it('should not try to authenticate the user with the password', function() {
  255. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  256. return this.SudoModeHandler.authenticate.callCount.should.equal(0)
  257. })
  258. it('should not activate sudo mode', function() {
  259. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  260. return this.SudoModeHandler.activateSudoMode.callCount.should.equal(0)
  261. })
  262. it('should not send back a json response', function() {
  263. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  264. return this.res.json.callCount.should.equal(0)
  265. })
  266. })
  267. describe('when getUser does not find a user', function() {
  268. beforeEach(function() {
  269. this.UserGetter.getUser = sinon.stub().callsArgWith(2, null, null)
  270. return (this.next = sinon.stub())
  271. })
  272. it('should return next with an error', function() {
  273. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  274. this.next.callCount.should.equal(1)
  275. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  276. })
  277. it('should get the user from storage', function() {
  278. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  279. this.UserGetter.getUser.callCount.should.equal(1)
  280. return this.UserGetter.getUser
  281. .calledWith('some_object_id', { email: 1 })
  282. .should.equal(true)
  283. })
  284. it('should not try to authenticate the user with the password', function() {
  285. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  286. return this.SudoModeHandler.authenticate.callCount.should.equal(0)
  287. })
  288. it('should not activate sudo mode', function() {
  289. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  290. return this.SudoModeHandler.activateSudoMode.callCount.should.equal(0)
  291. })
  292. it('should not send back a json response', function() {
  293. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  294. return this.res.json.callCount.should.equal(0)
  295. })
  296. })
  297. describe('when authentication fails', function() {
  298. beforeEach(function() {
  299. this.SudoModeHandler.authenticate = sinon
  300. .stub()
  301. .callsArgWith(2, null, null)
  302. this.res.json = sinon.stub()
  303. return (this.req.i18n = { translate: sinon.stub() })
  304. })
  305. it('should send back a failure message', function() {
  306. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  307. this.res.json.callCount.should.equal(1)
  308. expect(this.res.json.lastCall.args[0]).to.have.keys(['message'])
  309. expect(this.res.json.lastCall.args[0].message).to.have.keys([
  310. 'text',
  311. 'type'
  312. ])
  313. this.req.i18n.translate.callCount.should.equal(1)
  314. return this.req.i18n.translate.calledWith('invalid_password')
  315. })
  316. it('should get the user from storage', function() {
  317. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  318. this.UserGetter.getUser.callCount.should.equal(1)
  319. return this.UserGetter.getUser
  320. .calledWith('some_object_id', { email: 1 })
  321. .should.equal(true)
  322. })
  323. it('should try to authenticate the user with the password', function() {
  324. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  325. this.SudoModeHandler.authenticate.callCount.should.equal(1)
  326. return this.SudoModeHandler.authenticate
  327. .calledWith(this.user.email, this.password)
  328. .should.equal(true)
  329. })
  330. it('should not activate sudo mode', function() {
  331. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  332. return this.SudoModeHandler.activateSudoMode.callCount.should.equal(0)
  333. })
  334. })
  335. describe('when authentication produces an error', function() {
  336. beforeEach(function() {
  337. this.SudoModeHandler.authenticate = sinon
  338. .stub()
  339. .callsArgWith(2, new Error('woops'))
  340. return (this.next = sinon.stub())
  341. })
  342. it('should return next with an error', function() {
  343. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  344. this.next.callCount.should.equal(1)
  345. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  346. })
  347. it('should get the user from storage', function() {
  348. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  349. this.UserGetter.getUser.callCount.should.equal(1)
  350. return this.UserGetter.getUser
  351. .calledWith('some_object_id', { email: 1 })
  352. .should.equal(true)
  353. })
  354. it('should try to authenticate the user with the password', function() {
  355. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  356. this.SudoModeHandler.authenticate.callCount.should.equal(1)
  357. return this.SudoModeHandler.authenticate
  358. .calledWith(this.user.email, this.password)
  359. .should.equal(true)
  360. })
  361. it('should not activate sudo mode', function() {
  362. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  363. return this.SudoModeHandler.activateSudoMode.callCount.should.equal(0)
  364. })
  365. })
  366. describe('when sudo mode activation produces an error', function() {
  367. beforeEach(function() {
  368. this.SudoModeHandler.activateSudoMode = sinon
  369. .stub()
  370. .callsArgWith(1, new Error('woops'))
  371. return (this.next = sinon.stub())
  372. })
  373. it('should return next with an error', function() {
  374. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  375. this.next.callCount.should.equal(1)
  376. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  377. })
  378. it('should get the user from storage', function() {
  379. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  380. this.UserGetter.getUser.callCount.should.equal(1)
  381. return this.UserGetter.getUser
  382. .calledWith('some_object_id', { email: 1 })
  383. .should.equal(true)
  384. })
  385. it('should try to authenticate the user with the password', function() {
  386. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  387. this.SudoModeHandler.authenticate.callCount.should.equal(1)
  388. return this.SudoModeHandler.authenticate
  389. .calledWith(this.user.email, this.password)
  390. .should.equal(true)
  391. })
  392. it('should have tried to activate sudo mode', function() {
  393. this.SudoModeController.submitPassword(this.req, this.res, this.next)
  394. this.SudoModeHandler.activateSudoMode.callCount.should.equal(1)
  395. return this.SudoModeHandler.activateSudoMode
  396. .calledWith(this.user._id)
  397. .should.equal(true)
  398. })
  399. })
  400. })
  401. })
  402. })