TokenAccessControllerTests.coffee 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  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. @project =
  18. _id: @projectId
  19. publicAccesLevel: 'tokenBased'
  20. tokens:
  21. readOnly: @readOnlyToken
  22. readAndWrite: @readAndWriteToken
  23. @userId = ObjectId()
  24. @TokenAccessController = SandboxedModule.require modulePath, requires:
  25. '../Project/ProjectController': @ProjectController = {}
  26. '../Authentication/AuthenticationController': @AuthenticationController = {}
  27. './TokenAccessHandler': @TokenAccessHandler = {}
  28. 'logger-sharelatex': {log: sinon.stub(), err: sinon.stub()}
  29. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString())
  30. describe 'readAndWriteToken', ->
  31. beforeEach ->
  32. describe 'when all goes well', ->
  33. beforeEach ->
  34. @req = new MockRequest()
  35. @res = new MockResponse()
  36. @next = sinon.stub()
  37. @req.params['read_and_write_token'] = @readAndWriteToken
  38. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  39. .callsArgWith(1, null, @project)
  40. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  41. .callsArgWith(2, null)
  42. @ProjectController.loadEditor = sinon.stub()
  43. @TokenAccessController.readAndWriteToken @req, @res, @next
  44. it 'should try to find a project with this token', (done) ->
  45. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  46. .to.equal 1
  47. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  48. .to.equal true
  49. done()
  50. it 'should add the user to the project with read-write access', (done) ->
  51. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  52. .to.equal 1
  53. expect(@TokenAccessHandler.addReadAndWriteUserToProject.calledWith(
  54. @userId.toString(), @projectId
  55. ))
  56. .to.equal true
  57. done()
  58. it 'should pass control to loadEditor', (done) ->
  59. expect(@req.params.Project_id).to.equal @projectId.toString()
  60. expect(@ProjectController.loadEditor.callCount).to.equal 1
  61. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  62. done()
  63. describe 'when findProject produces an error', ->
  64. beforeEach ->
  65. @req = new MockRequest()
  66. @res = new MockResponse()
  67. @next = sinon.stub()
  68. @req.params['read_and_write_token'] = @readAndWriteToken
  69. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  70. .callsArgWith(1, new Error('woops'))
  71. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  72. .callsArgWith(2, null)
  73. @ProjectController.loadEditor = sinon.stub()
  74. @TokenAccessController.readAndWriteToken @req, @res, @next
  75. it 'should try to find a project with this token', (done) ->
  76. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  77. .to.equal 1
  78. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  79. .to.equal true
  80. done()
  81. it 'should not add the user to the project with read-write access', (done) ->
  82. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  83. .to.equal 0
  84. done()
  85. it 'should not pass control to loadEditor', (done) ->
  86. expect(@ProjectController.loadEditor.callCount).to.equal 0
  87. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  88. done()
  89. it 'should call next with an error', (done) ->
  90. expect(@next.callCount).to.equal 1
  91. expect(@next.lastCall.args[0]).to.be.instanceof Error
  92. done()
  93. describe 'when findProject does not find a project', ->
  94. beforeEach ->
  95. @req = new MockRequest()
  96. @res = new MockResponse()
  97. @next = sinon.stub()
  98. @req.params['read_and_write_token'] = @readAndWriteToken
  99. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  100. .callsArgWith(1, null, null)
  101. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  102. .callsArgWith(2, null)
  103. @ProjectController.loadEditor = sinon.stub()
  104. @TokenAccessController.readAndWriteToken @req, @res, @next
  105. it 'should try to find a project with this token', (done) ->
  106. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  107. .to.equal 1
  108. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  109. .to.equal true
  110. done()
  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 not pass control to loadEditor', (done) ->
  116. expect(@ProjectController.loadEditor.callCount).to.equal 0
  117. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  118. done()
  119. it 'should call next with a not-found error', (done) ->
  120. expect(@next.callCount).to.equal 1
  121. expect(@next.lastCall.args[0]).to.be.instanceof Error
  122. done()
  123. describe 'when adding user to project produces an error', ->
  124. beforeEach ->
  125. @req = new MockRequest()
  126. @res = new MockResponse()
  127. @next = sinon.stub()
  128. @req.params['read_and_write_token'] = @readAndWriteToken
  129. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  130. .callsArgWith(1, null, @project)
  131. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  132. .callsArgWith(2, new Error('woops'))
  133. @ProjectController.loadEditor = sinon.stub()
  134. @TokenAccessController.readAndWriteToken @req, @res, @next
  135. it 'should try to find a project with this token', (done) ->
  136. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  137. .to.equal 1
  138. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  139. .to.equal true
  140. done()
  141. it 'should add the user to the project with read-write access', (done) ->
  142. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  143. .to.equal 1
  144. expect(@TokenAccessHandler.addReadAndWriteUserToProject.calledWith(
  145. @userId.toString(), @projectId
  146. ))
  147. .to.equal true
  148. done()
  149. it 'should not pass control to loadEditor', (done) ->
  150. expect(@ProjectController.loadEditor.callCount).to.equal 0
  151. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  152. done()
  153. it 'should call next with an error', (done) ->
  154. expect(@next.callCount).to.equal 1
  155. expect(@next.lastCall.args[0]).to.be.instanceof Error
  156. done()
  157. describe 'readOnlyToken', ->
  158. beforeEach ->
  159. describe 'with a user', ->
  160. beforeEach ->
  161. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString())
  162. describe 'when all goes well', ->
  163. beforeEach ->
  164. @req = new MockRequest()
  165. @res = new MockResponse()
  166. @next = sinon.stub()
  167. @req.params['read_only_token'] = @readOnlyToken
  168. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  169. .callsArgWith(1, null, @project)
  170. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  171. .callsArgWith(2, null)
  172. @ProjectController.loadEditor = sinon.stub()
  173. @TokenAccessController.readOnlyToken @req, @res, @next
  174. it 'should try to find a project with this token', (done) ->
  175. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  176. .to.equal 1
  177. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  178. .to.equal true
  179. done()
  180. it 'should add the user to the project with read-only access', (done) ->
  181. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  182. .to.equal 1
  183. expect(@TokenAccessHandler.addReadOnlyUserToProject.calledWith(
  184. @userId.toString(), @projectId
  185. ))
  186. .to.equal true
  187. done()
  188. it 'should pass control to loadEditor', (done) ->
  189. expect(@req.params.Project_id).to.equal @projectId.toString()
  190. expect(@ProjectController.loadEditor.callCount).to.equal 1
  191. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  192. done()
  193. describe 'when findProject produces an error', ->
  194. beforeEach ->
  195. @req = new MockRequest()
  196. @res = new MockResponse()
  197. @next = sinon.stub()
  198. @req.params['read_only_token'] = @readOnlyToken
  199. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  200. .callsArgWith(1, new Error('woops'))
  201. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  202. .callsArgWith(2, null)
  203. @ProjectController.loadEditor = sinon.stub()
  204. @TokenAccessController.readOnlyToken @req, @res, @next
  205. it 'should try to find a project with this token', (done) ->
  206. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  207. .to.equal 1
  208. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  209. .to.equal true
  210. done()
  211. it 'should not add the user to the project with read-only access', (done) ->
  212. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  213. .to.equal 0
  214. done()
  215. it 'should not pass control to loadEditor', (done) ->
  216. expect(@ProjectController.loadEditor.callCount).to.equal 0
  217. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  218. done()
  219. it 'should call next with an error', (done) ->
  220. expect(@next.callCount).to.equal 1
  221. expect(@next.lastCall.args[0]).to.be.instanceof Error
  222. done()
  223. describe 'when findProject does not find a project', ->
  224. beforeEach ->
  225. @req = new MockRequest()
  226. @res = new MockResponse()
  227. @next = sinon.stub()
  228. @req.params['read_only_token'] = @readOnlyToken
  229. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  230. .callsArgWith(1, null, null)
  231. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  232. .callsArgWith(2, null)
  233. @ProjectController.loadEditor = sinon.stub()
  234. @TokenAccessController.readOnlyToken @req, @res, @next
  235. it 'should try to find a project with this token', (done) ->
  236. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  237. .to.equal 1
  238. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  239. .to.equal true
  240. done()
  241. it 'should not add the user to the project with read-only access', (done) ->
  242. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  243. .to.equal 0
  244. done()
  245. it 'should not pass control to loadEditor', (done) ->
  246. expect(@ProjectController.loadEditor.callCount).to.equal 0
  247. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  248. done()
  249. it 'should call next with a not-found error', (done) ->
  250. expect(@next.callCount).to.equal 1
  251. expect(@next.lastCall.args[0]).to.be.instanceof Error
  252. done()
  253. describe 'when adding user to project produces an error', ->
  254. beforeEach ->
  255. @req = new MockRequest()
  256. @res = new MockResponse()
  257. @next = sinon.stub()
  258. @req.params['read_only_token'] = @readOnlyToken
  259. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  260. .callsArgWith(1, null, @project)
  261. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  262. .callsArgWith(2, new Error('woops'))
  263. @ProjectController.loadEditor = sinon.stub()
  264. @TokenAccessController.readOnlyToken @req, @res, @next
  265. it 'should try to find a project with this token', (done) ->
  266. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  267. .to.equal 1
  268. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  269. .to.equal true
  270. done()
  271. it 'should add the user to the project with read-only access', (done) ->
  272. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  273. .to.equal 1
  274. expect(@TokenAccessHandler.addReadOnlyUserToProject.calledWith(
  275. @userId.toString(), @projectId
  276. ))
  277. .to.equal true
  278. done()
  279. it 'should not pass control to loadEditor', (done) ->
  280. expect(@ProjectController.loadEditor.callCount).to.equal 0
  281. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  282. done()
  283. it 'should call next with an error', (done) ->
  284. expect(@next.callCount).to.equal 1
  285. expect(@next.lastCall.args[0]).to.be.instanceof Error
  286. done()
  287. describe 'anonymous', ->
  288. beforeEach ->
  289. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(null)
  290. @TokenAccessHandler.grantSessionReadOnlyTokenAccess = sinon.stub()
  291. describe 'when all goes well', ->
  292. beforeEach ->
  293. @req = new MockRequest()
  294. @res = new MockResponse()
  295. @next = sinon.stub()
  296. @req.params['read_only_token'] = @readOnlyToken
  297. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  298. .callsArgWith(1, null, @project)
  299. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  300. .callsArgWith(2, null)
  301. @ProjectController.loadEditor = sinon.stub()
  302. @TokenAccessController.readOnlyToken @req, @res, @next
  303. it 'should try to find a project with this token', (done) ->
  304. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  305. .to.equal 1
  306. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  307. .to.equal true
  308. done()
  309. it 'should give the user session read-only access', (done) ->
  310. expect(@TokenAccessHandler.grantSessionReadOnlyTokenAccess.callCount)
  311. .to.equal 1
  312. expect(@TokenAccessHandler.grantSessionReadOnlyTokenAccess.calledWith(
  313. @req, @projectId, @readOnlyToken
  314. ))
  315. .to.equal true
  316. done()
  317. it 'should not add the user to the project with read-only access', (done) ->
  318. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  319. .to.equal 0
  320. done()
  321. it 'should pass control to loadEditor', (done) ->
  322. expect(@req.params.Project_id).to.equal @projectId.toString()
  323. expect(@req._anonToken).to.equal @readOnlyToken
  324. expect(@ProjectController.loadEditor.callCount).to.equal 1
  325. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  326. done()
  327. describe 'when findProject produces an error', ->
  328. beforeEach ->
  329. @req = new MockRequest()
  330. @res = new MockResponse()
  331. @next = sinon.stub()
  332. @req.params['read_only_token'] = @readOnlyToken
  333. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  334. .callsArgWith(1, new Error('woops'))
  335. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  336. .callsArgWith(2, null)
  337. @ProjectController.loadEditor = sinon.stub()
  338. @TokenAccessController.readOnlyToken @req, @res, @next
  339. it 'should try to find a project with this token', (done) ->
  340. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  341. .to.equal 1
  342. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  343. .to.equal true
  344. done()
  345. it 'should not give the user session read-only access', (done) ->
  346. expect(@TokenAccessHandler.grantSessionReadOnlyTokenAccess.callCount)
  347. .to.equal 0
  348. done()
  349. it 'should not add the user to the project with read-only access', (done) ->
  350. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  351. .to.equal 0
  352. done()
  353. it 'should not pass control to loadEditor', (done) ->
  354. expect(@ProjectController.loadEditor.callCount).to.equal 0
  355. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  356. done()
  357. it 'should call next with an error', (done) ->
  358. expect(@next.callCount).to.equal 1
  359. expect(@next.lastCall.args[0]).to.be.instanceof Error
  360. done()
  361. describe 'when findProject does not find a project', ->
  362. beforeEach ->
  363. @req = new MockRequest()
  364. @res = new MockResponse()
  365. @next = sinon.stub()
  366. @req.params['read_only_token'] = @readOnlyToken
  367. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  368. .callsArgWith(1, null, null)
  369. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  370. .callsArgWith(2, null)
  371. @ProjectController.loadEditor = sinon.stub()
  372. @TokenAccessController.readOnlyToken @req, @res, @next
  373. it 'should try to find a project with this token', (done) ->
  374. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  375. .to.equal 1
  376. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  377. .to.equal true
  378. done()
  379. it 'should not give the user session read-only access', (done) ->
  380. expect(@TokenAccessHandler.grantSessionReadOnlyTokenAccess.callCount)
  381. .to.equal 0
  382. done()
  383. it 'should not pass control to loadEditor', (done) ->
  384. expect(@ProjectController.loadEditor.callCount).to.equal 0
  385. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  386. done()
  387. it 'should not add the user to the project with read-only access', (done) ->
  388. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  389. .to.equal 0
  390. done()
  391. it 'should call next with a not-found error', (done) ->
  392. expect(@next.callCount).to.equal 1
  393. expect(@next.lastCall.args[0]).to.be.instanceof Error
  394. done()