TokenAccessControllerTests.coffee 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  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. @next = sinon.stub()
  134. @req.params['read_and_write_token'] = @readAndWriteToken
  135. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  136. .callsArgWith(1, null, @project)
  137. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  138. .callsArgWith(2, null)
  139. @ProjectController.loadEditor = sinon.stub()
  140. @TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
  141. @TokenAccessController.readAndWriteToken @req, @res, @next
  142. it 'should not add the user to the project with read-write access', (done) ->
  143. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  144. .to.equal 0
  145. done()
  146. it 'should give the user session token access', (done) ->
  147. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  148. .to.equal 0
  149. done()
  150. it 'should not pass control to loadEditor', (done) ->
  151. expect(@ProjectController.loadEditor.callCount).to.equal 0
  152. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  153. done()
  154. it 'should call next with an error', (done) ->
  155. expect(@next.callCount).to.equal 1
  156. expect(@next.lastCall.args[0]).to.be.instanceof Error
  157. done()
  158. describe 'when findProject produces an error', ->
  159. beforeEach ->
  160. @req = new MockRequest()
  161. @res = new MockResponse()
  162. @next = sinon.stub()
  163. @req.params['read_and_write_token'] = @readAndWriteToken
  164. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  165. .callsArgWith(1, new Error('woops'))
  166. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  167. .callsArgWith(2, null)
  168. @ProjectController.loadEditor = sinon.stub()
  169. @TokenAccessController.readAndWriteToken @req, @res, @next
  170. it 'should try to find a project with this token', (done) ->
  171. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  172. .to.equal 1
  173. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  174. .to.equal true
  175. done()
  176. it 'should not add the user to the project with read-write access', (done) ->
  177. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  178. .to.equal 0
  179. done()
  180. it 'should not pass control to loadEditor', (done) ->
  181. expect(@ProjectController.loadEditor.callCount).to.equal 0
  182. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  183. done()
  184. it 'should call next with an error', (done) ->
  185. expect(@next.callCount).to.equal 1
  186. expect(@next.lastCall.args[0]).to.be.instanceof Error
  187. done()
  188. describe 'when findProject does not find a project', ->
  189. beforeEach ->
  190. describe 'when user is present', ->
  191. beforeEach ->
  192. @AuthenticationController.getLoggedInUserId =
  193. sinon.stub().returns(@userId.toString())
  194. describe 'when token access is off, but user has higher access anyway', ->
  195. beforeEach ->
  196. @req = new MockRequest()
  197. @res = new MockResponse()
  198. @res.redirect = sinon.stub()
  199. @next = sinon.stub()
  200. @req.params['read_and_write_token'] = @readAndWriteToken
  201. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  202. .callsArgWith(1, null, null)
  203. @TokenAccessHandler.findProjectWithHigherAccess =
  204. sinon.stub()
  205. .callsArgWith(2, null, @project)
  206. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  207. .callsArgWith(2, null)
  208. @ProjectController.loadEditor = sinon.stub()
  209. @TokenAccessController.readAndWriteToken @req, @res, @next
  210. it 'should try to find a project with this token', (done) ->
  211. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  212. .to.equal 1
  213. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken
  214. .calledWith(@readAndWriteToken)
  215. ).to.equal true
  216. done()
  217. it 'should check if user has higher access to the token project', (done) ->
  218. expect(
  219. @TokenAccessHandler.findProjectWithHigherAccess.callCount
  220. ).to.equal 1
  221. done()
  222. it 'should not add the user to the project with read-write access', (done) ->
  223. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  224. .to.equal 0
  225. done()
  226. it 'should not pass control to loadEditor', (done) ->
  227. expect(@ProjectController.loadEditor.callCount).to.equal 0
  228. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  229. done()
  230. it 'should not call next with a not-found error', (done) ->
  231. expect(@next.callCount).to.equal 0
  232. done()
  233. it 'should redirect to the canonical project url', (done) ->
  234. expect(@res.redirect.callCount).to.equal 1
  235. expect(@res.redirect.calledWith(302, "/project/#{@project._id}")).to.equal true
  236. done()
  237. describe 'when higher access is not available', ->
  238. beforeEach ->
  239. @req = new MockRequest()
  240. @res = new MockResponse()
  241. @next = sinon.stub()
  242. @req.params['read_and_write_token'] = @readAndWriteToken
  243. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  244. .callsArgWith(1, null, null)
  245. @TokenAccessHandler.findProjectWithHigherAccess =
  246. sinon.stub()
  247. .callsArgWith(2, null, null)
  248. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  249. .callsArgWith(2, null)
  250. @ProjectController.loadEditor = sinon.stub()
  251. @TokenAccessController.readAndWriteToken @req, @res, @next
  252. it 'should try to find a project with this token', (done) ->
  253. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  254. .to.equal 1
  255. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(
  256. @readAndWriteToken
  257. )).to.equal true
  258. done()
  259. it 'should check if user has higher access to the token project', (done) ->
  260. expect(
  261. @TokenAccessHandler.findProjectWithHigherAccess.callCount
  262. ).to.equal 1
  263. done()
  264. it 'should not add the user to the project with read-write access', (done) ->
  265. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  266. .to.equal 0
  267. done()
  268. it 'should not pass control to loadEditor', (done) ->
  269. expect(@ProjectController.loadEditor.callCount).to.equal 0
  270. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  271. done()
  272. it 'should call next with a not-found error', (done) ->
  273. expect(@next.callCount).to.equal 1
  274. expect(@next.lastCall.args[0]).to.be.instanceof Error
  275. done()
  276. describe 'when adding user to project produces an error', ->
  277. beforeEach ->
  278. @req = new MockRequest()
  279. @res = new MockResponse()
  280. @next = sinon.stub()
  281. @req.params['read_and_write_token'] = @readAndWriteToken
  282. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  283. .callsArgWith(1, null, @project)
  284. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  285. .callsArgWith(2, new Error('woops'))
  286. @ProjectController.loadEditor = sinon.stub()
  287. @TokenAccessController.readAndWriteToken @req, @res, @next
  288. it 'should try to find a project with this token', (done) ->
  289. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  290. .to.equal 1
  291. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  292. .to.equal true
  293. done()
  294. it 'should add the user to the project with read-write access', (done) ->
  295. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  296. .to.equal 1
  297. expect(@TokenAccessHandler.addReadAndWriteUserToProject.calledWith(
  298. @userId.toString(), @projectId
  299. ))
  300. .to.equal true
  301. done()
  302. it 'should not pass control to loadEditor', (done) ->
  303. expect(@ProjectController.loadEditor.callCount).to.equal 0
  304. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  305. done()
  306. it 'should call next with an error', (done) ->
  307. expect(@next.callCount).to.equal 1
  308. expect(@next.lastCall.args[0]).to.be.instanceof Error
  309. done()
  310. describe 'readOnlyToken', ->
  311. beforeEach ->
  312. describe 'with a user', ->
  313. beforeEach ->
  314. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString())
  315. describe 'when all goes well', ->
  316. beforeEach ->
  317. @req = new MockRequest()
  318. @res = new MockResponse()
  319. @next = sinon.stub()
  320. @req.params['read_only_token'] = @readOnlyToken
  321. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  322. .callsArgWith(1, null, @project)
  323. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  324. .callsArgWith(2, null)
  325. @ProjectController.loadEditor = sinon.stub()
  326. @TokenAccessController.readOnlyToken @req, @res, @next
  327. it 'should try to find a project with this token', (done) ->
  328. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  329. .to.equal 1
  330. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  331. .to.equal true
  332. done()
  333. it 'should add the user to the project with read-only access', (done) ->
  334. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  335. .to.equal 1
  336. expect(@TokenAccessHandler.addReadOnlyUserToProject.calledWith(
  337. @userId.toString(), @projectId
  338. ))
  339. .to.equal true
  340. done()
  341. it 'should pass control to loadEditor', (done) ->
  342. expect(@req.params.Project_id).to.equal @projectId.toString()
  343. expect(@ProjectController.loadEditor.callCount).to.equal 1
  344. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  345. done()
  346. describe 'when the user is already the owner', ->
  347. beforeEach ->
  348. @req = new MockRequest()
  349. @res = new MockResponse()
  350. @next = sinon.stub()
  351. @req.params['read_only_token'] = @readOnlyToken
  352. @project.owner_ref = @userId
  353. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  354. .callsArgWith(1, null, @project)
  355. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  356. .callsArgWith(2, null)
  357. @ProjectController.loadEditor = sinon.stub()
  358. @TokenAccessController.readOnlyToken @req, @res, @next
  359. it 'should try to find a project with this token', (done) ->
  360. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  361. .to.equal 1
  362. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  363. .to.equal true
  364. done()
  365. it 'should not add the user to the project with read-only access', (done) ->
  366. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  367. .to.equal 0
  368. done()
  369. it 'should pass control to loadEditor', (done) ->
  370. expect(@req.params.Project_id).to.equal @projectId.toString()
  371. expect(@ProjectController.loadEditor.callCount).to.equal 1
  372. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  373. done()
  374. describe 'when findProject produces an error', ->
  375. beforeEach ->
  376. @req = new MockRequest()
  377. @res = new MockResponse()
  378. @next = sinon.stub()
  379. @req.params['read_only_token'] = @readOnlyToken
  380. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  381. .callsArgWith(1, new Error('woops'))
  382. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  383. .callsArgWith(2, null)
  384. @ProjectController.loadEditor = sinon.stub()
  385. @TokenAccessController.readOnlyToken @req, @res, @next
  386. it 'should try to find a project with this token', (done) ->
  387. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  388. .to.equal 1
  389. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  390. .to.equal true
  391. done()
  392. it 'should not add the user to the project with read-only access', (done) ->
  393. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  394. .to.equal 0
  395. done()
  396. it 'should not pass control to loadEditor', (done) ->
  397. expect(@ProjectController.loadEditor.callCount).to.equal 0
  398. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  399. done()
  400. it 'should call next with an error', (done) ->
  401. expect(@next.callCount).to.equal 1
  402. expect(@next.lastCall.args[0]).to.be.instanceof Error
  403. done()
  404. ##
  405. describe 'when findProject does not find a project', ->
  406. beforeEach ->
  407. describe 'when token access is off, but user has higher access anyway', ->
  408. beforeEach ->
  409. @req = new MockRequest()
  410. @res = new MockResponse()
  411. @res.redirect = sinon.stub()
  412. @next = sinon.stub()
  413. @req.params['read_and_write_token'] = @readAndWriteToken
  414. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  415. .callsArgWith(1, null, null)
  416. @TokenAccessHandler.findProjectWithHigherAccess =
  417. sinon.stub()
  418. .callsArgWith(2, null, @project)
  419. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  420. .callsArgWith(2, null)
  421. @ProjectController.loadEditor = sinon.stub()
  422. @TokenAccessController.readAndWriteToken @req, @res, @next
  423. it 'should try to find a project with this token', (done) ->
  424. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  425. .to.equal 1
  426. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  427. .to.equal true
  428. done()
  429. it 'should check if user has higher access to the token project', (done) ->
  430. expect(
  431. @TokenAccessHandler.findProjectWithHigherAccess.callCount
  432. ).to.equal 1
  433. done()
  434. it 'should not add the user to the project with read-write access', (done) ->
  435. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  436. .to.equal 0
  437. done()
  438. it 'should not pass control to loadEditor', (done) ->
  439. expect(@ProjectController.loadEditor.callCount).to.equal 0
  440. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  441. done()
  442. it 'should not call next with a not-found error', (done) ->
  443. expect(@next.callCount).to.equal 0
  444. done()
  445. it 'should redirect to the canonical project url', (done) ->
  446. expect(@res.redirect.callCount).to.equal 1
  447. expect(@res.redirect.calledWith(302, "/project/#{@project._id}")).to.equal true
  448. done()
  449. describe 'when higher access is not available', ->
  450. beforeEach ->
  451. @req = new MockRequest()
  452. @res = new MockResponse()
  453. @next = sinon.stub()
  454. @req.params['read_and_write_token'] = @readAndWriteToken
  455. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  456. .callsArgWith(1, null, null)
  457. @TokenAccessHandler.findProjectWithHigherAccess =
  458. sinon.stub()
  459. .callsArgWith(2, null, null)
  460. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  461. .callsArgWith(2, null)
  462. @ProjectController.loadEditor = sinon.stub()
  463. @TokenAccessController.readAndWriteToken @req, @res, @next
  464. it 'should try to find a project with this token', (done) ->
  465. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  466. .to.equal 1
  467. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(
  468. @readAndWriteToken
  469. )).to.equal true
  470. done()
  471. it 'should check if user has higher access to the token project', (done) ->
  472. expect(
  473. @TokenAccessHandler.findProjectWithHigherAccess.callCount
  474. ).to.equal 1
  475. done()
  476. it 'should not add the user to the project with read-write access', (done) ->
  477. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  478. .to.equal 0
  479. done()
  480. it 'should not pass control to loadEditor', (done) ->
  481. expect(@ProjectController.loadEditor.callCount).to.equal 0
  482. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  483. done()
  484. it 'should call next with a not-found error', (done) ->
  485. expect(@next.callCount).to.equal 1
  486. expect(@next.lastCall.args[0]).to.be.instanceof Error
  487. done()
  488. describe 'when adding user to project produces an error', ->
  489. beforeEach ->
  490. @req = new MockRequest()
  491. @res = new MockResponse()
  492. @next = sinon.stub()
  493. @req.params['read_only_token'] = @readOnlyToken
  494. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  495. .callsArgWith(1, null, @project)
  496. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  497. .callsArgWith(2, new Error('woops'))
  498. @ProjectController.loadEditor = sinon.stub()
  499. @TokenAccessController.readOnlyToken @req, @res, @next
  500. it 'should try to find a project with this token', (done) ->
  501. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  502. .to.equal 1
  503. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  504. .to.equal true
  505. done()
  506. it 'should add the user to the project with read-only access', (done) ->
  507. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  508. .to.equal 1
  509. expect(@TokenAccessHandler.addReadOnlyUserToProject.calledWith(
  510. @userId.toString(), @projectId
  511. ))
  512. .to.equal true
  513. done()
  514. it 'should not pass control to loadEditor', (done) ->
  515. expect(@ProjectController.loadEditor.callCount).to.equal 0
  516. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  517. done()
  518. it 'should call next with an error', (done) ->
  519. expect(@next.callCount).to.equal 1
  520. expect(@next.lastCall.args[0]).to.be.instanceof Error
  521. done()
  522. describe 'anonymous', ->
  523. beforeEach ->
  524. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(null)
  525. @TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
  526. describe 'when all goes well', ->
  527. beforeEach ->
  528. @req = new MockRequest()
  529. @res = new MockResponse()
  530. @next = sinon.stub()
  531. @req.params['read_only_token'] = @readOnlyToken
  532. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  533. .callsArgWith(1, null, @project)
  534. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  535. .callsArgWith(2, null)
  536. @ProjectController.loadEditor = sinon.stub()
  537. @TokenAccessController.readOnlyToken @req, @res, @next
  538. it 'should try to find a project with this token', (done) ->
  539. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  540. .to.equal 1
  541. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  542. .to.equal true
  543. done()
  544. it 'should give the user session read-only access', (done) ->
  545. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  546. .to.equal 1
  547. expect(@TokenAccessHandler.grantSessionTokenAccess.calledWith(
  548. @req, @projectId, @readOnlyToken
  549. ))
  550. .to.equal true
  551. done()
  552. it 'should not add the user to the project with read-only access', (done) ->
  553. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  554. .to.equal 0
  555. done()
  556. it 'should pass control to loadEditor', (done) ->
  557. expect(@req.params.Project_id).to.equal @projectId.toString()
  558. expect(@req._anonymousAccessToken).to.equal @readOnlyToken
  559. expect(@ProjectController.loadEditor.callCount).to.equal 1
  560. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  561. done()
  562. describe 'when findProject produces an error', ->
  563. beforeEach ->
  564. @req = new MockRequest()
  565. @res = new MockResponse()
  566. @next = sinon.stub()
  567. @req.params['read_only_token'] = @readOnlyToken
  568. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  569. .callsArgWith(1, new Error('woops'))
  570. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  571. .callsArgWith(2, null)
  572. @ProjectController.loadEditor = sinon.stub()
  573. @TokenAccessController.readOnlyToken @req, @res, @next
  574. it 'should try to find a project with this token', (done) ->
  575. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  576. .to.equal 1
  577. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  578. .to.equal true
  579. done()
  580. it 'should not give the user session read-only access', (done) ->
  581. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  582. .to.equal 0
  583. done()
  584. it 'should not add the user to the project with read-only access', (done) ->
  585. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  586. .to.equal 0
  587. done()
  588. it 'should not pass control to loadEditor', (done) ->
  589. expect(@ProjectController.loadEditor.callCount).to.equal 0
  590. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  591. done()
  592. it 'should call next with an error', (done) ->
  593. expect(@next.callCount).to.equal 1
  594. expect(@next.lastCall.args[0]).to.be.instanceof Error
  595. done()
  596. describe 'when findProject does not find a project', ->
  597. beforeEach ->
  598. @req = new MockRequest()
  599. @res = new MockResponse()
  600. @next = sinon.stub()
  601. @req.params['read_only_token'] = @readOnlyToken
  602. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  603. .callsArgWith(1, null, null)
  604. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  605. .callsArgWith(2, null)
  606. @ProjectController.loadEditor = sinon.stub()
  607. @TokenAccessController.readOnlyToken @req, @res, @next
  608. it 'should try to find a project with this token', (done) ->
  609. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  610. .to.equal 1
  611. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  612. .to.equal true
  613. done()
  614. it 'should not give the user session read-only access', (done) ->
  615. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  616. .to.equal 0
  617. done()
  618. it 'should not pass control to loadEditor', (done) ->
  619. expect(@ProjectController.loadEditor.callCount).to.equal 0
  620. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  621. done()
  622. it 'should not add the user to the project with read-only access', (done) ->
  623. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  624. .to.equal 0
  625. done()
  626. it 'should call next with a not-found error', (done) ->
  627. expect(@next.callCount).to.equal 1
  628. expect(@next.lastCall.args[0]).to.be.instanceof Error
  629. done()