TokenAccessTests.js 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. const { expect } = require('chai')
  2. const async = require('async')
  3. const MockV1Api = require('./helpers/MockV1Api')
  4. const User = require('./helpers/User')
  5. const request = require('./helpers/request')
  6. const settings = require('settings-sharelatex')
  7. const { db, ObjectId } = require('../../../app/src/infrastructure/mongojs')
  8. const tryReadAccess = (user, projectId, test, callback) =>
  9. async.series(
  10. [
  11. cb =>
  12. user.request.get(`/project/${projectId}`, (error, response, body) => {
  13. if (error != null) {
  14. return cb(error)
  15. }
  16. test(response, body)
  17. cb()
  18. }),
  19. cb =>
  20. user.request.get(
  21. `/project/${projectId}/download/zip`,
  22. (error, response, body) => {
  23. if (error != null) {
  24. return cb(error)
  25. }
  26. test(response, body)
  27. cb()
  28. }
  29. )
  30. ],
  31. callback
  32. )
  33. const tryReadOnlyTokenAccess = (user, token, test, callback) =>
  34. user.request.get(`/read/${token}`, (error, response, body) => {
  35. if (error != null) {
  36. return callback(error)
  37. }
  38. test(response, body)
  39. callback()
  40. })
  41. const tryReadAndWriteTokenAccess = (user, token, test, callback) =>
  42. user.request.get(`/${token}`, (error, response, body) => {
  43. if (error != null) {
  44. return callback(error)
  45. }
  46. test(response, body)
  47. callback()
  48. })
  49. const tryContentAccess = (user, projcetId, test, callback) => {
  50. // The real-time service calls this end point to determine the user's
  51. // permissions.
  52. let userId
  53. if (user.id != null) {
  54. userId = user.id
  55. } else {
  56. userId = 'anonymous-user'
  57. }
  58. request.post(
  59. {
  60. url: `/project/${projcetId}/join`,
  61. qs: { user_id: userId },
  62. auth: {
  63. user: settings.apis.web.user,
  64. pass: settings.apis.web.pass,
  65. sendImmediately: true
  66. },
  67. json: true,
  68. jar: false
  69. },
  70. (error, response, body) => {
  71. if (error != null) {
  72. return callback(error)
  73. }
  74. test(response, body)
  75. callback()
  76. }
  77. )
  78. }
  79. const tryAnonContentAccess = (user, projectId, token, test, callback) => {
  80. // The real-time service calls this end point to determine the user's
  81. // permissions.
  82. let userId
  83. if (user.id != null) {
  84. userId = user.id
  85. } else {
  86. userId = 'anonymous-user'
  87. }
  88. request.post(
  89. {
  90. url: `/project/${projectId}/join`,
  91. qs: { user_id: userId },
  92. auth: {
  93. user: settings.apis.web.user,
  94. pass: settings.apis.web.pass,
  95. sendImmediately: true
  96. },
  97. headers: {
  98. 'x-sl-anonymous-access-token': token
  99. },
  100. json: true,
  101. jar: false
  102. },
  103. (error, response, body) => {
  104. if (error != null) {
  105. return callback(error)
  106. }
  107. test(response, body)
  108. callback()
  109. }
  110. )
  111. }
  112. describe('TokenAccess', function() {
  113. beforeEach(function(done) {
  114. this.timeout(90000)
  115. this.owner = new User()
  116. this.other1 = new User()
  117. this.other2 = new User()
  118. this.anon = new User()
  119. async.parallel(
  120. [
  121. cb => this.owner.login(cb),
  122. cb => this.other1.login(cb),
  123. cb => this.other2.login(cb),
  124. cb => this.anon.getCsrfToken(cb)
  125. ],
  126. done
  127. )
  128. })
  129. describe('no token-access', function() {
  130. beforeEach(function(done) {
  131. this.owner.createProject(
  132. `token-ro-test${Math.random()}`,
  133. (err, projectId) => {
  134. if (err != null) {
  135. return done(err)
  136. }
  137. this.projectId = projectId
  138. // Note, never made token-based,
  139. // thus no tokens
  140. done()
  141. }
  142. )
  143. })
  144. it('should deny access ', function(done) {
  145. async.series(
  146. [
  147. cb => {
  148. tryReadAccess(
  149. this.other1,
  150. this.projectId,
  151. (response, body) => {
  152. expect(response.statusCode).to.equal(302)
  153. expect(body).to.match(/.*\/restricted.*/)
  154. },
  155. cb
  156. )
  157. },
  158. cb => {
  159. tryContentAccess(
  160. this.other1,
  161. this.projectId,
  162. (response, body) => {
  163. expect(response.statusCode).to.equal(403)
  164. expect(body).to.equal('Forbidden')
  165. },
  166. cb
  167. )
  168. }
  169. ],
  170. done
  171. )
  172. })
  173. })
  174. describe('read-only token', function() {
  175. beforeEach(function(done) {
  176. this.owner.createProject(
  177. `token-ro-test${Math.random()}`,
  178. (err, projectId) => {
  179. if (err != null) {
  180. return done(err)
  181. }
  182. this.projectId = projectId
  183. this.owner.makeTokenBased(this.projectId, err => {
  184. if (err != null) {
  185. return done(err)
  186. }
  187. this.owner.getProject(this.projectId, (err, project) => {
  188. if (err != null) {
  189. return done(err)
  190. }
  191. this.tokens = project.tokens
  192. done()
  193. })
  194. })
  195. }
  196. )
  197. })
  198. it('allow the user read-only access to the project', function(done) {
  199. async.series(
  200. [
  201. cb => {
  202. // deny access before token is used
  203. tryReadAccess(
  204. this.other1,
  205. this.projectId,
  206. (response, body) => {
  207. expect(response.statusCode).to.equal(302)
  208. expect(body).to.match(/.*\/restricted.*/)
  209. },
  210. cb
  211. )
  212. },
  213. cb => {
  214. // use token
  215. tryReadOnlyTokenAccess(
  216. this.other1,
  217. this.tokens.readOnly,
  218. (response, body) => {
  219. expect(response.statusCode).to.equal(200)
  220. },
  221. cb
  222. )
  223. },
  224. cb => {
  225. // allow content access read-only
  226. tryContentAccess(
  227. this.other1,
  228. this.projectId,
  229. (response, body) => {
  230. expect(body.privilegeLevel).to.equal('readOnly')
  231. expect(body.isRestrictedUser).to.equal(true)
  232. expect(body.project.owner).to.have.keys('_id')
  233. expect(body.project.owner).to.not.have.any.keys(
  234. 'email',
  235. 'first_name',
  236. 'last_name'
  237. )
  238. },
  239. cb
  240. )
  241. }
  242. ],
  243. done
  244. )
  245. })
  246. describe('made private again', function() {
  247. beforeEach(function(done) {
  248. this.owner.makePrivate(this.projectId, () => setTimeout(done, 1000))
  249. })
  250. it('should not allow the user to access the project', function(done) {
  251. async.series(
  252. [
  253. // no access before token is used
  254. cb =>
  255. tryReadAccess(
  256. this.other1,
  257. this.projectId,
  258. (response, body) => {
  259. expect(response.statusCode).to.equal(302)
  260. expect(body).to.match(/.*\/restricted.*/)
  261. },
  262. cb
  263. ),
  264. cb =>
  265. tryReadOnlyTokenAccess(
  266. this.other1,
  267. this.tokens.readOnly,
  268. (response, body) => {
  269. expect(response.statusCode).to.equal(404)
  270. },
  271. cb
  272. ),
  273. cb =>
  274. tryContentAccess(
  275. this.other1,
  276. this.projectId,
  277. (response, body) => {
  278. expect(response.statusCode).to.equal(403)
  279. expect(body).to.equal('Forbidden')
  280. },
  281. cb
  282. )
  283. ],
  284. done
  285. )
  286. })
  287. })
  288. })
  289. describe('anonymous read-only token', function() {
  290. beforeEach(function(done) {
  291. this.owner.createProject(
  292. `token-anon-ro-test${Math.random()}`,
  293. (err, projectId) => {
  294. if (err != null) {
  295. return done(err)
  296. }
  297. this.projectId = projectId
  298. this.owner.makeTokenBased(this.projectId, err => {
  299. if (err != null) {
  300. return done(err)
  301. }
  302. this.owner.getProject(this.projectId, (err, project) => {
  303. if (err != null) {
  304. return done(err)
  305. }
  306. this.tokens = project.tokens
  307. done()
  308. })
  309. })
  310. }
  311. )
  312. })
  313. it('should allow the user to access project via read-only token url', function(done) {
  314. async.series(
  315. [
  316. cb =>
  317. tryReadAccess(
  318. this.anon,
  319. this.projectId,
  320. (response, body) => {
  321. expect(response.statusCode).to.equal(302)
  322. expect(body).to.match(/.*\/restricted.*/)
  323. },
  324. cb
  325. ),
  326. cb =>
  327. tryReadOnlyTokenAccess(
  328. this.anon,
  329. this.tokens.readOnly,
  330. (response, body) => {
  331. expect(response.statusCode).to.equal(200)
  332. },
  333. cb
  334. ),
  335. cb =>
  336. tryAnonContentAccess(
  337. this.anon,
  338. this.projectId,
  339. this.tokens.readOnly,
  340. (response, body) => {
  341. expect(body.privilegeLevel).to.equal('readOnly')
  342. expect(body.isRestrictedUser).to.equal(true)
  343. expect(body.project.owner).to.have.keys('_id')
  344. expect(body.project.owner).to.not.have.any.keys(
  345. 'email',
  346. 'first_name',
  347. 'last_name'
  348. )
  349. },
  350. cb
  351. )
  352. ],
  353. done
  354. )
  355. })
  356. describe('made private again', function() {
  357. beforeEach(function(done) {
  358. this.owner.makePrivate(this.projectId, () => setTimeout(done, 1000))
  359. })
  360. it('should deny access to project', function(done) {
  361. async.series(
  362. [
  363. cb =>
  364. tryReadAccess(
  365. this.anon,
  366. this.projectId,
  367. (response, body) => {
  368. expect(response.statusCode).to.equal(302)
  369. expect(body).to.match(/.*\/restricted.*/)
  370. },
  371. cb
  372. ),
  373. // should not allow the user to access read-only token
  374. cb =>
  375. tryReadOnlyTokenAccess(
  376. this.anon,
  377. this.tokens.readOnly,
  378. (response, body) => {
  379. expect(response.statusCode).to.equal(404)
  380. },
  381. cb
  382. ),
  383. // should not allow the user to join the project
  384. cb =>
  385. tryAnonContentAccess(
  386. this.anon,
  387. this.projectId,
  388. this.tokens.readOnly,
  389. (response, body) => {
  390. expect(response.statusCode).to.equal(403)
  391. expect(body).to.equal('Forbidden')
  392. },
  393. cb
  394. )
  395. ],
  396. done
  397. )
  398. })
  399. })
  400. })
  401. describe('read-and-write token', function() {
  402. beforeEach(function(done) {
  403. this.owner.createProject(
  404. `token-rw-test${Math.random()}`,
  405. (err, projectId) => {
  406. if (err != null) {
  407. return done(err)
  408. }
  409. this.projectId = projectId
  410. this.owner.makeTokenBased(this.projectId, err => {
  411. if (err != null) {
  412. return done(err)
  413. }
  414. this.owner.getProject(this.projectId, (err, project) => {
  415. if (err != null) {
  416. return done(err)
  417. }
  418. this.tokens = project.tokens
  419. done()
  420. })
  421. })
  422. }
  423. )
  424. })
  425. it('should allow the user to access project via read-and-write token url', function(done) {
  426. async.series(
  427. [
  428. // deny access before the token is used
  429. cb =>
  430. tryReadAccess(
  431. this.other1,
  432. this.projectId,
  433. (response, body) => {
  434. expect(response.statusCode).to.equal(302)
  435. expect(response.headers.location).to.match(/\/restricted.*/)
  436. expect(body).to.match(/.*\/restricted.*/)
  437. },
  438. cb
  439. ),
  440. cb =>
  441. tryReadAndWriteTokenAccess(
  442. this.other1,
  443. this.tokens.readAndWrite,
  444. (response, body) => {
  445. expect(response.statusCode).to.equal(200)
  446. },
  447. cb
  448. ),
  449. cb =>
  450. tryContentAccess(
  451. this.other1,
  452. this.projectId,
  453. (response, body) => {
  454. expect(body.privilegeLevel).to.equal('readAndWrite')
  455. expect(body.isRestrictedUser).to.equal(false)
  456. expect(body.project.owner).to.have.all.keys(
  457. '_id',
  458. 'email',
  459. 'first_name',
  460. 'last_name',
  461. 'privileges',
  462. 'signUpDate'
  463. )
  464. },
  465. cb
  466. )
  467. ],
  468. done
  469. )
  470. })
  471. describe('made private again', function() {
  472. beforeEach(function(done) {
  473. this.owner.makePrivate(this.projectId, () => setTimeout(done, 1000))
  474. })
  475. it('should deny access to project', function(done) {
  476. async.series(
  477. [
  478. cb => {
  479. tryReadAccess(
  480. this.other1,
  481. this.projectId,
  482. (response, body) => {
  483. expect(response.statusCode).to.equal(302)
  484. expect(body).to.match(/.*\/restricted.*/)
  485. },
  486. cb
  487. )
  488. },
  489. cb => {
  490. tryReadAndWriteTokenAccess(
  491. this.other1,
  492. this.tokens.readAndWrite,
  493. (response, body) => {
  494. expect(response.statusCode).to.equal(404)
  495. },
  496. cb
  497. )
  498. },
  499. cb => {
  500. tryContentAccess(
  501. this.other1,
  502. this.projectId,
  503. (response, body) => {
  504. expect(response.statusCode).to.equal(403)
  505. expect(body).to.equal('Forbidden')
  506. },
  507. cb
  508. )
  509. }
  510. ],
  511. done
  512. )
  513. })
  514. })
  515. })
  516. if (!settings.allowAnonymousReadAndWriteSharing) {
  517. describe('anonymous read-and-write token, disabled', function() {
  518. beforeEach(function(done) {
  519. this.owner.createProject(
  520. `token-anon-rw-test${Math.random()}`,
  521. (err, projectId) => {
  522. if (err != null) {
  523. return done(err)
  524. }
  525. this.projectId = projectId
  526. this.owner.makeTokenBased(this.projectId, err => {
  527. if (err != null) {
  528. return done(err)
  529. }
  530. this.owner.getProject(this.projectId, (err, project) => {
  531. if (err != null) {
  532. return done(err)
  533. }
  534. this.tokens = project.tokens
  535. done()
  536. })
  537. })
  538. }
  539. )
  540. })
  541. it('should not allow the user to access read-and-write token', function(done) {
  542. async.series(
  543. [
  544. cb =>
  545. tryReadAccess(
  546. this.anon,
  547. this.projectId,
  548. (response, body) => {
  549. expect(response.statusCode).to.equal(302)
  550. expect(body).to.match(/.*\/restricted.*/)
  551. },
  552. cb
  553. ),
  554. cb =>
  555. tryReadAndWriteTokenAccess(
  556. this.anon,
  557. this.tokens.readAndWrite,
  558. (response, body) => {
  559. expect(response.statusCode).to.equal(302)
  560. expect(body).to.match(/.*\/restricted.*/)
  561. },
  562. cb
  563. ),
  564. cb =>
  565. tryAnonContentAccess(
  566. this.anon,
  567. this.projectId,
  568. this.tokens.readAndWrite,
  569. (response, body) => {
  570. expect(response.statusCode).to.equal(403)
  571. expect(body).to.equal('Forbidden')
  572. },
  573. cb
  574. )
  575. ],
  576. done
  577. )
  578. })
  579. })
  580. } else {
  581. describe('anonymous read-and-write token, enabled', function() {
  582. beforeEach(function(done) {
  583. this.owner.createProject(
  584. `token-anon-rw-test${Math.random()}`,
  585. (err, projectId) => {
  586. if (err != null) {
  587. return done(err)
  588. }
  589. this.projectId = projectId
  590. this.owner.makeTokenBased(this.projectId, err => {
  591. if (err != null) {
  592. return done(err)
  593. }
  594. this.owner.getProject(this.projectId, (err, project) => {
  595. if (err != null) {
  596. return done(err)
  597. }
  598. this.tokens = project.tokens
  599. done()
  600. })
  601. })
  602. }
  603. )
  604. })
  605. it('should allow the user to access project via read-and-write token url', function(done) {
  606. async.series(
  607. [
  608. cb =>
  609. tryReadAccess(
  610. this.anon,
  611. this.projectId,
  612. (response, body) => {
  613. expect(response.statusCode).to.equal(302)
  614. expect(body).to.match(/.*\/restricted.*/)
  615. },
  616. cb
  617. ),
  618. cb =>
  619. tryReadAndWriteTokenAccess(
  620. this.anon,
  621. this.tokens.readAndWrite,
  622. (response, body) => {
  623. expect(response.statusCode).to.equal(200)
  624. },
  625. cb
  626. ),
  627. cb =>
  628. tryAnonContentAccess(
  629. this.anon,
  630. this.projectId,
  631. this.tokens.readAndWrite,
  632. (response, body) => {
  633. expect(body.privilegeLevel).to.equal('readAndWrite')
  634. },
  635. cb
  636. )
  637. ],
  638. done
  639. )
  640. })
  641. describe('made private again', function() {
  642. beforeEach(function(done) {
  643. this.owner.makePrivate(this.projectId, () => setTimeout(done, 1000))
  644. })
  645. it('should not allow the user to access read-and-write token', function(done) {
  646. async.series(
  647. [
  648. cb =>
  649. tryReadAccess(
  650. this.anon,
  651. this.projectId,
  652. (response, body) => {
  653. expect(response.statusCode).to.equal(302)
  654. expect(body).to.match(/.*\/restricted.*/)
  655. },
  656. cb
  657. ),
  658. cb =>
  659. tryReadAndWriteTokenAccess(
  660. this.anon,
  661. this.tokens.readAndWrite,
  662. (response, body) => {
  663. expect(response.statusCode).to.equal(404)
  664. },
  665. cb
  666. ),
  667. cb =>
  668. tryAnonContentAccess(
  669. this.anon,
  670. this.projectId,
  671. this.tokens.readAndWrite,
  672. (response, body) => {
  673. expect(response.statusCode).to.equal(403)
  674. expect(body).to.equal('Forbidden')
  675. },
  676. cb
  677. )
  678. ],
  679. done
  680. )
  681. })
  682. })
  683. })
  684. }
  685. describe('private overleaf project', function() {
  686. beforeEach(function(done) {
  687. this.owner.createProject('overleaf-import', (err, projectId) => {
  688. expect(err).not.to.exist
  689. this.projectId = projectId
  690. this.owner.makeTokenBased(this.projectId, err => {
  691. expect(err).not.to.exist
  692. this.owner.getProject(this.projectId, (err, project) => {
  693. expect(err).not.to.exist
  694. this.tokens = project.tokens
  695. this.owner.makePrivate(this.projectId, () => {
  696. db.projects.update(
  697. { _id: project._id },
  698. {
  699. $set: {
  700. overleaf: { id: 1234 }
  701. }
  702. },
  703. err => {
  704. expect(err).not.to.exist
  705. done()
  706. }
  707. )
  708. })
  709. })
  710. })
  711. })
  712. })
  713. it('should only allow the owner access to the project', function(done) {
  714. async.series(
  715. [
  716. // should redirect to canonical path, when owner uses read-write token
  717. cb =>
  718. tryReadAndWriteTokenAccess(
  719. this.owner,
  720. this.tokens.readAndWrite,
  721. (response, body) => {
  722. expect(response.statusCode).to.equal(302)
  723. expect(response.headers.location).to.equal(
  724. `/project/${this.projectId}`
  725. )
  726. },
  727. cb
  728. ),
  729. cb =>
  730. tryReadAccess(
  731. this.owner,
  732. this.projectId,
  733. (response, body) => {
  734. expect(response.statusCode).to.equal(200)
  735. },
  736. cb
  737. ),
  738. cb =>
  739. tryContentAccess(
  740. this.owner,
  741. this.projectId,
  742. (response, body) => {
  743. expect(body.privilegeLevel).to.equal('owner')
  744. },
  745. cb
  746. ),
  747. // non-owner should be denied access
  748. cb =>
  749. tryContentAccess(
  750. this.other2,
  751. this.projectId,
  752. (response, body) => {
  753. expect(response.statusCode).to.equal(403)
  754. expect(body).to.equal('Forbidden')
  755. },
  756. cb
  757. )
  758. ],
  759. done
  760. )
  761. })
  762. })
  763. describe('private project, with higher access', function() {
  764. beforeEach(function(done) {
  765. this.owner.createProject(
  766. `higher-access-test-${Math.random()}`,
  767. (err, projectId) => {
  768. expect(err).not.to.exist
  769. this.projectId = projectId
  770. this.owner.addUserToProject(
  771. this.projectId,
  772. this.other1,
  773. 'readAndWrite',
  774. err => {
  775. expect(err).not.to.exist
  776. this.owner.makeTokenBased(this.projectId, err => {
  777. expect(err).not.to.exist
  778. this.owner.getProject(this.projectId, (err, project) => {
  779. expect(err).not.to.exist
  780. this.tokens = project.tokens
  781. this.owner.makePrivate(this.projectId, () => {
  782. setTimeout(done, 1000)
  783. })
  784. })
  785. })
  786. }
  787. )
  788. }
  789. )
  790. })
  791. it('should allow the user access to the project', function(done) {
  792. async.series(
  793. [
  794. // should redirect to canonical path, when user uses read-write token
  795. cb =>
  796. tryReadAndWriteTokenAccess(
  797. this.other1,
  798. this.tokens.readAndWrite,
  799. (response, body) => {
  800. expect(response.statusCode).to.equal(302)
  801. expect(response.headers.location).to.equal(
  802. `/project/${this.projectId}`
  803. )
  804. },
  805. cb
  806. ),
  807. // should redirect to canonical path, when user uses read-only token
  808. cb =>
  809. tryReadOnlyTokenAccess(
  810. this.other1,
  811. this.tokens.readOnly,
  812. (response, body) => {
  813. expect(response.statusCode).to.equal(302)
  814. expect(response.headers.location).to.equal(
  815. `/project/${this.projectId}`
  816. )
  817. },
  818. cb
  819. ),
  820. // should allow the user access to the project
  821. cb =>
  822. tryReadAccess(
  823. this.other1,
  824. this.projectId,
  825. (response, body) => {
  826. expect(response.statusCode).to.equal(200)
  827. },
  828. cb
  829. ),
  830. // should allow user to join the project
  831. cb =>
  832. tryContentAccess(
  833. this.other1,
  834. this.projectId,
  835. (response, body) => {
  836. expect(body.privilegeLevel).to.equal('readAndWrite')
  837. },
  838. cb
  839. ),
  840. // should not allow a different user to join the project
  841. cb =>
  842. tryContentAccess(
  843. this.other2,
  844. this.projectId,
  845. (response, body) => {
  846. expect(response.statusCode).to.equal(403)
  847. expect(body).to.equal('Forbidden')
  848. },
  849. cb
  850. )
  851. ],
  852. done
  853. )
  854. })
  855. })
  856. describe('unimported v1 project', function() {
  857. beforeEach(function() {
  858. settings.overleaf = { host: 'http://localhost:5000' }
  859. })
  860. afterEach(function() {
  861. delete settings.overleaf
  862. })
  863. it('should show error page for read and write token', function(done) {
  864. const unimportedV1Token = '123abc'
  865. tryReadAndWriteTokenAccess(
  866. this.owner,
  867. unimportedV1Token,
  868. (response, body) => {
  869. expect(response.statusCode).to.equal(400)
  870. },
  871. done
  872. )
  873. })
  874. it('should show error page for read only token to v1', function(done) {
  875. const unimportedV1Token = 'abcd'
  876. tryReadOnlyTokenAccess(
  877. this.owner,
  878. unimportedV1Token,
  879. (response, body) => {
  880. expect(response.statusCode).to.equal(400)
  881. },
  882. done
  883. )
  884. })
  885. })
  886. describe('importing v1 project', function() {
  887. beforeEach(function(done) {
  888. settings.projectImportingCheckMaxCreateDelta = 3600
  889. settings.overleaf = { host: 'http://localhost:5000' }
  890. this.owner.createProject(
  891. `token-rw-test${Math.random()}`,
  892. (err, projectId) => {
  893. if (err != null) {
  894. return done(err)
  895. }
  896. this.projectId = projectId
  897. this.owner.makeTokenBased(this.projectId, err => {
  898. if (err != null) {
  899. return done(err)
  900. }
  901. db.projects.update(
  902. { _id: ObjectId(projectId) },
  903. { $set: { overleaf: { id: 1234 } } },
  904. err => {
  905. if (err != null) {
  906. return done(err)
  907. }
  908. this.owner.getProject(this.projectId, (err, project) => {
  909. if (err != null) {
  910. return done(err)
  911. }
  912. this.tokens = project.tokens
  913. MockV1Api.setDocExported(this.tokens.readAndWrite, {
  914. exporting: true
  915. })
  916. MockV1Api.setDocExported(this.tokens.readOnly, {
  917. exporting: true
  918. })
  919. done()
  920. })
  921. }
  922. )
  923. })
  924. }
  925. )
  926. })
  927. afterEach(function() {
  928. delete settings.projectImportingCheckMaxCreateDelta
  929. delete settings.overleaf
  930. })
  931. it('should show importing page for read, and read-write tokens', function(done) {
  932. async.series(
  933. [
  934. cb =>
  935. tryReadAndWriteTokenAccess(
  936. this.owner,
  937. this.tokens.readAndWrite,
  938. (response, body) => {
  939. expect(response.statusCode).to.equal(200)
  940. expect(body).to.include('ImportingController')
  941. },
  942. cb
  943. ),
  944. cb =>
  945. tryReadOnlyTokenAccess(
  946. this.owner,
  947. this.tokens.readOnly,
  948. (response, body) => {
  949. expect(response.statusCode).to.equal(200)
  950. expect(body).to.include('ImportingController')
  951. },
  952. cb
  953. )
  954. ],
  955. done
  956. )
  957. })
  958. describe('when importing check not configured', function() {
  959. beforeEach(function() {
  960. delete settings.projectImportingCheckMaxCreateDelta
  961. })
  962. it('should load editor', function(done) {
  963. tryReadAndWriteTokenAccess(
  964. this.owner,
  965. this.tokens.readAndWrite,
  966. (response, body) => {
  967. expect(response.statusCode).to.equal(200)
  968. expect(body).to.include('IdeController')
  969. },
  970. done
  971. )
  972. })
  973. })
  974. })
  975. })