TokenAccessControllerTests.coffee 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. should = require('chai').should()
  2. SandboxedModule = require('sandboxed-module')
  3. assert = require('assert')
  4. path = require('path')
  5. sinon = require('sinon')
  6. modulePath = path.join __dirname, "../../../../app/js/Features/TokenAccess/TokenAccessController"
  7. expect = require("chai").expect
  8. ObjectId = require("mongojs").ObjectId
  9. MockRequest = require('../helpers/MockRequest')
  10. MockResponse = require('../helpers/MockResponse')
  11. Errors = require "../../../../app/js/Features/Errors/Errors.js"
  12. describe "TokenAccessController", ->
  13. beforeEach ->
  14. @readOnlyToken = 'somereadonlytoken'
  15. @readAndWriteToken = '42somereadandwritetoken'
  16. @projectId = ObjectId()
  17. @ownerId = 'owner'
  18. @project =
  19. _id: @projectId
  20. publicAccesLevel: 'tokenBased'
  21. tokens:
  22. readOnly: @readOnlyToken
  23. readAndWrite: @readAndWriteToken
  24. owner_ref: @ownerId
  25. @userId = ObjectId()
  26. @TokenAccessController = SandboxedModule.require modulePath, requires:
  27. '../Project/ProjectController': @ProjectController = {}
  28. '../Authentication/AuthenticationController': @AuthenticationController = {}
  29. './TokenAccessHandler': @TokenAccessHandler = {}
  30. 'logger-sharelatex': {log: sinon.stub(), err: sinon.stub()}
  31. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString())
  32. describe 'readAndWriteToken', ->
  33. beforeEach ->
  34. describe 'when all goes well', ->
  35. beforeEach ->
  36. @req = new MockRequest()
  37. @res = new MockResponse()
  38. @next = sinon.stub()
  39. @req.params['read_and_write_token'] = @readAndWriteToken
  40. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  41. .callsArgWith(1, null, @project)
  42. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  43. .callsArgWith(2, null)
  44. @ProjectController.loadEditor = sinon.stub()
  45. @TokenAccessController.readAndWriteToken @req, @res, @next
  46. it 'should try to find a project with this token', (done) ->
  47. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  48. .to.equal 1
  49. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  50. .to.equal true
  51. done()
  52. it 'should add the user to the project with read-write access', (done) ->
  53. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  54. .to.equal 1
  55. expect(@TokenAccessHandler.addReadAndWriteUserToProject.calledWith(
  56. @userId.toString(), @projectId
  57. ))
  58. .to.equal true
  59. done()
  60. it 'should pass control to loadEditor', (done) ->
  61. expect(@req.params.Project_id).to.equal @projectId.toString()
  62. expect(@ProjectController.loadEditor.callCount).to.equal 1
  63. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  64. done()
  65. describe 'when the user is already the owner', ->
  66. beforeEach ->
  67. @req = new MockRequest()
  68. @res = new MockResponse()
  69. @next = sinon.stub()
  70. @req.params['read_and_write_token'] = @readAndWriteToken
  71. @project.owner_ref = @userId
  72. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  73. .callsArgWith(1, null, @project)
  74. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  75. .callsArgWith(2, null)
  76. @ProjectController.loadEditor = sinon.stub()
  77. @TokenAccessController.readAndWriteToken @req, @res, @next
  78. it 'should try to find a project with this token', (done) ->
  79. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  80. .to.equal 1
  81. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  82. .to.equal true
  83. done()
  84. it 'should not add the user to the project with read-write access', (done) ->
  85. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  86. .to.equal 0
  87. done()
  88. it 'should pass control to loadEditor', (done) ->
  89. expect(@req.params.Project_id).to.equal @projectId.toString()
  90. expect(@ProjectController.loadEditor.callCount).to.equal 1
  91. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  92. done()
  93. describe 'when there is no user', ->
  94. beforeEach ->
  95. @AuthenticationController.getLoggedInUserId =
  96. sinon.stub().returns(null)
  97. describe 'when anonymous read-write access is enabled', ->
  98. beforeEach ->
  99. @TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED = true
  100. @req = new MockRequest()
  101. @res = new MockResponse()
  102. @next = sinon.stub()
  103. @req.params['read_and_write_token'] = @readAndWriteToken
  104. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  105. .callsArgWith(1, null, @project)
  106. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  107. .callsArgWith(2, null)
  108. @ProjectController.loadEditor = sinon.stub()
  109. @TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
  110. @TokenAccessController.readAndWriteToken @req, @res, @next
  111. it 'should not add the user to the project with read-write access', (done) ->
  112. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  113. .to.equal 0
  114. done()
  115. it 'should give the user session token access', (done) ->
  116. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  117. .to.equal 1
  118. expect(@TokenAccessHandler.grantSessionTokenAccess.calledWith(
  119. @req, @projectId, @readAndWriteToken
  120. ))
  121. .to.equal true
  122. done()
  123. it 'should pass control to loadEditor', (done) ->
  124. expect(@req.params.Project_id).to.equal @projectId.toString()
  125. expect(@ProjectController.loadEditor.callCount).to.equal 1
  126. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  127. done()
  128. describe 'when anonymous read-write access is not enabled', ->
  129. beforeEach ->
  130. @TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED = false
  131. @req = new MockRequest()
  132. @res = new MockResponse()
  133. @res.redirect = sinon.stub()
  134. @next = sinon.stub()
  135. @req.params['read_and_write_token'] = @readAndWriteToken
  136. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  137. .callsArgWith(1, null, @project)
  138. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  139. .callsArgWith(2, null)
  140. @ProjectController.loadEditor = sinon.stub()
  141. @TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
  142. @TokenAccessController.readAndWriteToken @req, @res, @next
  143. it 'should not add the user to the project with read-write access', (done) ->
  144. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  145. .to.equal 0
  146. done()
  147. it 'should give the user session token access', (done) ->
  148. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  149. .to.equal 0
  150. done()
  151. it 'should not pass control to loadEditor', (done) ->
  152. expect(@ProjectController.loadEditor.callCount).to.equal 0
  153. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  154. done()
  155. it 'should redirect to restricted page', (done) ->
  156. expect(@res.redirect.callCount).to.equal 1
  157. expect(@res.redirect.calledWith('/restricted')).to.equal true
  158. done()
  159. describe 'when findProject produces an error', ->
  160. beforeEach ->
  161. @req = new MockRequest()
  162. @res = new MockResponse()
  163. @next = sinon.stub()
  164. @req.params['read_and_write_token'] = @readAndWriteToken
  165. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  166. .callsArgWith(1, new Error('woops'))
  167. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  168. .callsArgWith(2, null)
  169. @ProjectController.loadEditor = sinon.stub()
  170. @TokenAccessController.readAndWriteToken @req, @res, @next
  171. it 'should try to find a project with this token', (done) ->
  172. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  173. .to.equal 1
  174. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  175. .to.equal true
  176. done()
  177. it 'should not add the user to the project with read-write access', (done) ->
  178. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  179. .to.equal 0
  180. done()
  181. it 'should not pass control to loadEditor', (done) ->
  182. expect(@ProjectController.loadEditor.callCount).to.equal 0
  183. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  184. done()
  185. it 'should call next with an error', (done) ->
  186. expect(@next.callCount).to.equal 1
  187. expect(@next.lastCall.args[0]).to.be.instanceof Error
  188. done()
  189. describe 'when findProject does not find a project', ->
  190. beforeEach ->
  191. describe 'when user is present', ->
  192. beforeEach ->
  193. @AuthenticationController.getLoggedInUserId =
  194. sinon.stub().returns(@userId.toString())
  195. describe 'when token access is off, but user has higher access anyway', ->
  196. beforeEach ->
  197. @req = new MockRequest()
  198. @res = new MockResponse()
  199. @res.redirect = sinon.stub()
  200. @next = sinon.stub()
  201. @req.params['read_and_write_token'] = @readAndWriteToken
  202. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  203. .callsArgWith(1, null, null)
  204. @TokenAccessHandler.findProjectWithHigherAccess =
  205. sinon.stub()
  206. .callsArgWith(2, null, @project)
  207. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  208. .callsArgWith(2, null)
  209. @ProjectController.loadEditor = sinon.stub()
  210. @TokenAccessController.readAndWriteToken @req, @res, @next
  211. it 'should try to find a project with this token', (done) ->
  212. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  213. .to.equal 1
  214. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken
  215. .calledWith(@readAndWriteToken)
  216. ).to.equal true
  217. done()
  218. it 'should check if user has higher access to the token project', (done) ->
  219. expect(
  220. @TokenAccessHandler.findProjectWithHigherAccess.callCount
  221. ).to.equal 1
  222. done()
  223. it 'should not add the user to the project with read-write access', (done) ->
  224. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  225. .to.equal 0
  226. done()
  227. it 'should not pass control to loadEditor', (done) ->
  228. expect(@ProjectController.loadEditor.callCount).to.equal 0
  229. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  230. done()
  231. it 'should not call next with a not-found error', (done) ->
  232. expect(@next.callCount).to.equal 0
  233. done()
  234. it 'should redirect to the canonical project url', (done) ->
  235. expect(@res.redirect.callCount).to.equal 1
  236. expect(@res.redirect.calledWith(302, "/project/#{@project._id}")).to.equal true
  237. done()
  238. describe 'when higher access is not available', ->
  239. beforeEach ->
  240. @req = new MockRequest()
  241. @res = new MockResponse()
  242. @next = sinon.stub()
  243. @req.params['read_and_write_token'] = @readAndWriteToken
  244. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  245. .callsArgWith(1, null, null)
  246. @TokenAccessHandler.findProjectWithHigherAccess =
  247. sinon.stub()
  248. .callsArgWith(2, null, null)
  249. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  250. .callsArgWith(2, null)
  251. @ProjectController.loadEditor = sinon.stub()
  252. @TokenAccessController.readAndWriteToken @req, @res, @next
  253. it 'should try to find a project with this token', (done) ->
  254. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  255. .to.equal 1
  256. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(
  257. @readAndWriteToken
  258. )).to.equal true
  259. done()
  260. it 'should check if user has higher access to the token project', (done) ->
  261. expect(
  262. @TokenAccessHandler.findProjectWithHigherAccess.callCount
  263. ).to.equal 1
  264. done()
  265. it 'should not add the user to the project with read-write access', (done) ->
  266. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  267. .to.equal 0
  268. done()
  269. it 'should not pass control to loadEditor', (done) ->
  270. expect(@ProjectController.loadEditor.callCount).to.equal 0
  271. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  272. done()
  273. it 'should call next with a not-found error', (done) ->
  274. expect(@next.callCount).to.equal 1
  275. expect(@next.lastCall.args[0]).to.be.instanceof Error
  276. done()
  277. describe 'when adding user to project produces an error', ->
  278. beforeEach ->
  279. @req = new MockRequest()
  280. @res = new MockResponse()
  281. @next = sinon.stub()
  282. @req.params['read_and_write_token'] = @readAndWriteToken
  283. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  284. .callsArgWith(1, null, @project)
  285. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  286. .callsArgWith(2, new Error('woops'))
  287. @ProjectController.loadEditor = sinon.stub()
  288. @TokenAccessController.readAndWriteToken @req, @res, @next
  289. it 'should try to find a project with this token', (done) ->
  290. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  291. .to.equal 1
  292. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  293. .to.equal true
  294. done()
  295. it 'should add the user to the project with read-write access', (done) ->
  296. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  297. .to.equal 1
  298. expect(@TokenAccessHandler.addReadAndWriteUserToProject.calledWith(
  299. @userId.toString(), @projectId
  300. ))
  301. .to.equal true
  302. done()
  303. it 'should not pass control to loadEditor', (done) ->
  304. expect(@ProjectController.loadEditor.callCount).to.equal 0
  305. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  306. done()
  307. it 'should call next with an error', (done) ->
  308. expect(@next.callCount).to.equal 1
  309. expect(@next.lastCall.args[0]).to.be.instanceof Error
  310. done()
  311. describe 'readOnlyToken', ->
  312. beforeEach ->
  313. describe 'with a user', ->
  314. beforeEach ->
  315. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString())
  316. describe 'when all goes well', ->
  317. beforeEach ->
  318. @req = new MockRequest()
  319. @res = new MockResponse()
  320. @next = sinon.stub()
  321. @req.params['read_only_token'] = @readOnlyToken
  322. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  323. .callsArgWith(1, null, @project)
  324. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  325. .callsArgWith(2, null)
  326. @ProjectController.loadEditor = sinon.stub()
  327. @TokenAccessController.readOnlyToken @req, @res, @next
  328. it 'should try to find a project with this token', (done) ->
  329. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  330. .to.equal 1
  331. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  332. .to.equal true
  333. done()
  334. it 'should add the user to the project with read-only access', (done) ->
  335. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  336. .to.equal 1
  337. expect(@TokenAccessHandler.addReadOnlyUserToProject.calledWith(
  338. @userId.toString(), @projectId
  339. ))
  340. .to.equal true
  341. done()
  342. it 'should pass control to loadEditor', (done) ->
  343. expect(@req.params.Project_id).to.equal @projectId.toString()
  344. expect(@ProjectController.loadEditor.callCount).to.equal 1
  345. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  346. done()
  347. describe 'when the user is already the owner', ->
  348. beforeEach ->
  349. @req = new MockRequest()
  350. @res = new MockResponse()
  351. @next = sinon.stub()
  352. @req.params['read_only_token'] = @readOnlyToken
  353. @project.owner_ref = @userId
  354. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  355. .callsArgWith(1, null, @project)
  356. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  357. .callsArgWith(2, null)
  358. @ProjectController.loadEditor = sinon.stub()
  359. @TokenAccessController.readOnlyToken @req, @res, @next
  360. it 'should try to find a project with this token', (done) ->
  361. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  362. .to.equal 1
  363. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  364. .to.equal true
  365. done()
  366. it 'should not add the user to the project with read-only access', (done) ->
  367. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  368. .to.equal 0
  369. done()
  370. it 'should pass control to loadEditor', (done) ->
  371. expect(@req.params.Project_id).to.equal @projectId.toString()
  372. expect(@ProjectController.loadEditor.callCount).to.equal 1
  373. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  374. done()
  375. describe 'when findProject produces an error', ->
  376. beforeEach ->
  377. @req = new MockRequest()
  378. @res = new MockResponse()
  379. @next = sinon.stub()
  380. @req.params['read_only_token'] = @readOnlyToken
  381. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  382. .callsArgWith(1, new Error('woops'))
  383. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  384. .callsArgWith(2, null)
  385. @ProjectController.loadEditor = sinon.stub()
  386. @TokenAccessController.readOnlyToken @req, @res, @next
  387. it 'should try to find a project with this token', (done) ->
  388. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  389. .to.equal 1
  390. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  391. .to.equal true
  392. done()
  393. it 'should not add the user to the project with read-only access', (done) ->
  394. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  395. .to.equal 0
  396. done()
  397. it 'should not pass control to loadEditor', (done) ->
  398. expect(@ProjectController.loadEditor.callCount).to.equal 0
  399. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  400. done()
  401. it 'should call next with an error', (done) ->
  402. expect(@next.callCount).to.equal 1
  403. expect(@next.lastCall.args[0]).to.be.instanceof Error
  404. done()
  405. ##
  406. describe 'when findProject does not find a project', ->
  407. beforeEach ->
  408. describe 'when token access is off, but user has higher access anyway', ->
  409. beforeEach ->
  410. @req = new MockRequest()
  411. @res = new MockResponse()
  412. @res.redirect = sinon.stub()
  413. @next = sinon.stub()
  414. @req.params['read_and_write_token'] = @readAndWriteToken
  415. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  416. .callsArgWith(1, null, null)
  417. @TokenAccessHandler.findProjectWithHigherAccess =
  418. sinon.stub()
  419. .callsArgWith(2, null, @project)
  420. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  421. .callsArgWith(2, null)
  422. @ProjectController.loadEditor = sinon.stub()
  423. @TokenAccessController.readAndWriteToken @req, @res, @next
  424. it 'should try to find a project with this token', (done) ->
  425. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  426. .to.equal 1
  427. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  428. .to.equal true
  429. done()
  430. it 'should check if user has higher access to the token project', (done) ->
  431. expect(
  432. @TokenAccessHandler.findProjectWithHigherAccess.callCount
  433. ).to.equal 1
  434. done()
  435. it 'should not add the user to the project with read-write access', (done) ->
  436. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  437. .to.equal 0
  438. done()
  439. it 'should not pass control to loadEditor', (done) ->
  440. expect(@ProjectController.loadEditor.callCount).to.equal 0
  441. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  442. done()
  443. it 'should not call next with a not-found error', (done) ->
  444. expect(@next.callCount).to.equal 0
  445. done()
  446. it 'should redirect to the canonical project url', (done) ->
  447. expect(@res.redirect.callCount).to.equal 1
  448. expect(@res.redirect.calledWith(302, "/project/#{@project._id}")).to.equal true
  449. done()
  450. describe 'when higher access is not available', ->
  451. beforeEach ->
  452. @req = new MockRequest()
  453. @res = new MockResponse()
  454. @next = sinon.stub()
  455. @req.params['read_and_write_token'] = @readAndWriteToken
  456. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  457. .callsArgWith(1, null, null)
  458. @TokenAccessHandler.findProjectWithHigherAccess =
  459. sinon.stub()
  460. .callsArgWith(2, null, null)
  461. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  462. .callsArgWith(2, null)
  463. @ProjectController.loadEditor = sinon.stub()
  464. @TokenAccessController.readAndWriteToken @req, @res, @next
  465. it 'should try to find a project with this token', (done) ->
  466. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  467. .to.equal 1
  468. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(
  469. @readAndWriteToken
  470. )).to.equal true
  471. done()
  472. it 'should check if user has higher access to the token project', (done) ->
  473. expect(
  474. @TokenAccessHandler.findProjectWithHigherAccess.callCount
  475. ).to.equal 1
  476. done()
  477. it 'should not add the user to the project with read-write access', (done) ->
  478. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  479. .to.equal 0
  480. done()
  481. it 'should not pass control to loadEditor', (done) ->
  482. expect(@ProjectController.loadEditor.callCount).to.equal 0
  483. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  484. done()
  485. it 'should call next with a not-found error', (done) ->
  486. expect(@next.callCount).to.equal 1
  487. expect(@next.lastCall.args[0]).to.be.instanceof Error
  488. done()
  489. describe 'when adding user to project produces an error', ->
  490. beforeEach ->
  491. @req = new MockRequest()
  492. @res = new MockResponse()
  493. @next = sinon.stub()
  494. @req.params['read_only_token'] = @readOnlyToken
  495. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  496. .callsArgWith(1, null, @project)
  497. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  498. .callsArgWith(2, new Error('woops'))
  499. @ProjectController.loadEditor = sinon.stub()
  500. @TokenAccessController.readOnlyToken @req, @res, @next
  501. it 'should try to find a project with this token', (done) ->
  502. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  503. .to.equal 1
  504. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  505. .to.equal true
  506. done()
  507. it 'should add the user to the project with read-only access', (done) ->
  508. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  509. .to.equal 1
  510. expect(@TokenAccessHandler.addReadOnlyUserToProject.calledWith(
  511. @userId.toString(), @projectId
  512. ))
  513. .to.equal true
  514. done()
  515. it 'should not pass control to loadEditor', (done) ->
  516. expect(@ProjectController.loadEditor.callCount).to.equal 0
  517. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  518. done()
  519. it 'should call next with an error', (done) ->
  520. expect(@next.callCount).to.equal 1
  521. expect(@next.lastCall.args[0]).to.be.instanceof Error
  522. done()
  523. describe 'anonymous', ->
  524. beforeEach ->
  525. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(null)
  526. @TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
  527. describe 'when all goes well', ->
  528. beforeEach ->
  529. @req = new MockRequest()
  530. @res = new MockResponse()
  531. @next = sinon.stub()
  532. @req.params['read_only_token'] = @readOnlyToken
  533. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  534. .callsArgWith(1, null, @project)
  535. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  536. .callsArgWith(2, null)
  537. @ProjectController.loadEditor = sinon.stub()
  538. @TokenAccessController.readOnlyToken @req, @res, @next
  539. it 'should try to find a project with this token', (done) ->
  540. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  541. .to.equal 1
  542. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  543. .to.equal true
  544. done()
  545. it 'should give the user session read-only access', (done) ->
  546. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  547. .to.equal 1
  548. expect(@TokenAccessHandler.grantSessionTokenAccess.calledWith(
  549. @req, @projectId, @readOnlyToken
  550. ))
  551. .to.equal true
  552. done()
  553. it 'should not add the user to the project with read-only access', (done) ->
  554. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  555. .to.equal 0
  556. done()
  557. it 'should pass control to loadEditor', (done) ->
  558. expect(@req.params.Project_id).to.equal @projectId.toString()
  559. expect(@req._anonymousAccessToken).to.equal @readOnlyToken
  560. expect(@ProjectController.loadEditor.callCount).to.equal 1
  561. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  562. done()
  563. describe 'when findProject produces an error', ->
  564. beforeEach ->
  565. @req = new MockRequest()
  566. @res = new MockResponse()
  567. @next = sinon.stub()
  568. @req.params['read_only_token'] = @readOnlyToken
  569. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  570. .callsArgWith(1, new Error('woops'))
  571. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  572. .callsArgWith(2, null)
  573. @ProjectController.loadEditor = sinon.stub()
  574. @TokenAccessController.readOnlyToken @req, @res, @next
  575. it 'should try to find a project with this token', (done) ->
  576. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  577. .to.equal 1
  578. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  579. .to.equal true
  580. done()
  581. it 'should not give the user session read-only access', (done) ->
  582. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  583. .to.equal 0
  584. done()
  585. it 'should not add the user to the project with read-only access', (done) ->
  586. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  587. .to.equal 0
  588. done()
  589. it 'should not pass control to loadEditor', (done) ->
  590. expect(@ProjectController.loadEditor.callCount).to.equal 0
  591. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  592. done()
  593. it 'should call next with an error', (done) ->
  594. expect(@next.callCount).to.equal 1
  595. expect(@next.lastCall.args[0]).to.be.instanceof Error
  596. done()
  597. describe 'when findProject does not find a project', ->
  598. beforeEach ->
  599. @req = new MockRequest()
  600. @res = new MockResponse()
  601. @next = sinon.stub()
  602. @req.params['read_only_token'] = @readOnlyToken
  603. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  604. .callsArgWith(1, null, null)
  605. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  606. .callsArgWith(2, null)
  607. @ProjectController.loadEditor = sinon.stub()
  608. @TokenAccessController.readOnlyToken @req, @res, @next
  609. it 'should try to find a project with this token', (done) ->
  610. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  611. .to.equal 1
  612. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  613. .to.equal true
  614. done()
  615. it 'should not give the user session read-only access', (done) ->
  616. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  617. .to.equal 0
  618. done()
  619. it 'should not pass control to loadEditor', (done) ->
  620. expect(@ProjectController.loadEditor.callCount).to.equal 0
  621. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  622. done()
  623. it 'should not add the user to the project with read-only access', (done) ->
  624. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  625. .to.equal 0
  626. done()
  627. it 'should call next with a not-found error', (done) ->
  628. expect(@next.callCount).to.equal 1
  629. expect(@next.lastCall.args[0]).to.be.instanceof Error
  630. done()