Improve error reporting and show 404 when project ids are malformed

This commit is contained in:
James Allen
2016-03-18 15:59:12 +00:00
parent 88b8ce1f80
commit e7d67668e9
16 changed files with 222 additions and 113 deletions
@@ -4,6 +4,7 @@ should = chai.should()
expect = chai.expect
modulePath = "../../../../app/js/Features/Authorization/AuthorizationManager.js"
SandboxedModule = require('sandboxed-module')
Errors = require "../../../../app/js/Features/Errors/Errors.js"
describe "AuthorizationManager", ->
beforeEach ->
@@ -11,6 +12,7 @@ describe "AuthorizationManager", ->
"../Collaborators/CollaboratorsHandler": @CollaboratorsHandler = {}
"../../models/Project": Project: @Project = {}
"../../models/User": User: @User = {}
"../Errors/Errors": Errors
@user_id = "user-id-1"
@project_id = "project-id-1"
@callback = sinon.stub()
@@ -91,6 +93,16 @@ describe "AuthorizationManager", ->
it "should return the public privilege level", ->
@callback.calledWith(null, "readAndWrite", true).should.equal true
describe "when the project doesn't exist", ->
beforeEach ->
@Project.findOne
.withArgs({ _id: @project_id }, { publicAccesLevel: 1 })
.yields(null, null)
it "should return a NotFoundError", ->
@AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, (error) ->
error.should.be.instanceof Errors.NotFoundError
describe "canUserReadProject", ->
beforeEach ->
@@ -4,16 +4,21 @@ should = chai.should()
expect = chai.expect
modulePath = "../../../../app/js/Features/Authorization/AuthorizationMiddlewear.js"
SandboxedModule = require('sandboxed-module')
Errors = require "../../../../app/js/Features/Errors/Errors.js"
describe "AuthorizationMiddlewear", ->
beforeEach ->
@AuthorizationMiddlewear = SandboxedModule.require modulePath, requires:
"./AuthorizationManager": @AuthorizationManager = {}
"logger-sharelatex": {log: () ->}
"mongojs": ObjectId: @ObjectId = {}
"../Errors/Errors": Errors
@user_id = "user-id-123"
@project_id = "project-id-123"
@req = {}
@res = {}
@ObjectId.isValid = sinon.stub()
@ObjectId.isValid.withArgs(@project_id).returns true
@next = sinon.stub()
METHODS_TO_TEST = {
@@ -90,6 +95,17 @@ describe "AuthorizationMiddlewear", ->
@AuthorizationMiddlewear.redirectToRestricted
.calledWith(@req, @res, @next)
.should.equal true
describe "with malformed project id", ->
beforeEach ->
@req.params =
project_id: "blah"
@ObjectId.isValid = sinon.stub().returns false
it "should return a not found error", (done) ->
@AuthorizationMiddlewear[middlewearMethod] @req, @res, (error) ->
error.should.be.instanceof Errors.NotFoundError
done()
describe "ensureUserIsSiteAdmin", ->
beforeEach ->
@@ -5,6 +5,7 @@ path = require('path')
sinon = require('sinon')
modulePath = path.join __dirname, "../../../../app/js/Features/Collaborators/CollaboratorsHandler"
expect = require("chai").expect
Errors = require "../../../../app/js/Features/Errors/Errors.js"
describe "CollaboratorsHandler", ->
beforeEach ->
@@ -16,6 +17,7 @@ describe "CollaboratorsHandler", ->
"../../models/Project": Project: @Project = {}
"../Project/ProjectEntityHandler": @ProjectEntityHandler = {}
"./CollaboratorsEmailHandler": @CollaboratorsEmailHandler = {}
"../Errors/Errors": Errors
@project_id = "mock-project-id"
@user_id = "mock-user-id"
@@ -24,25 +26,35 @@ describe "CollaboratorsHandler", ->
@callback = sinon.stub()
describe "getMemberIdsWithPrivilegeLevels", ->
beforeEach ->
@Project.findOne = sinon.stub()
@Project.findOne.withArgs({_id: @project_id}, {owner_ref: 1, collaberator_refs: 1, readOnly_refs: 1}).yields(null, @project = {
owner_ref: [ "owner-ref" ]
readOnly_refs: [ "read-only-ref-1", "read-only-ref-2" ]
collaberator_refs: [ "read-write-ref-1", "read-write-ref-2" ]
})
@CollaboratorHandler.getMemberIdsWithPrivilegeLevels @project_id, @callback
describe "with project", ->
beforeEach ->
@Project.findOne = sinon.stub()
@Project.findOne.withArgs({_id: @project_id}, {owner_ref: 1, collaberator_refs: 1, readOnly_refs: 1}).yields(null, @project = {
owner_ref: [ "owner-ref" ]
readOnly_refs: [ "read-only-ref-1", "read-only-ref-2" ]
collaberator_refs: [ "read-write-ref-1", "read-write-ref-2" ]
})
@CollaboratorHandler.getMemberIdsWithPrivilegeLevels @project_id, @callback
it "should return an array of member ids with their privilege levels", ->
@callback
.calledWith(null, [
{ id: "owner-ref", privilegeLevel: "owner" }
{ id: "read-only-ref-1", privilegeLevel: "readOnly" }
{ id: "read-only-ref-2", privilegeLevel: "readOnly" }
{ id: "read-write-ref-1", privilegeLevel: "readAndWrite" }
{ id: "read-write-ref-2", privilegeLevel: "readAndWrite" }
])
.should.equal true
it "should return an array of member ids with their privilege levels", ->
@callback
.calledWith(null, [
{ id: "owner-ref", privilegeLevel: "owner" }
{ id: "read-only-ref-1", privilegeLevel: "readOnly" }
{ id: "read-only-ref-2", privilegeLevel: "readOnly" }
{ id: "read-write-ref-1", privilegeLevel: "readAndWrite" }
{ id: "read-write-ref-2", privilegeLevel: "readAndWrite" }
])
.should.equal true
describe "with a missing project", ->
beforeEach ->
@Project.findOne = sinon.stub().yields(null, null)
it "should return a NotFoundError", (done) ->
@CollaboratorHandler.getMemberIdsWithPrivilegeLevels @project_id, (error) ->
error.should.be.instanceof Errors.NotFoundError
done()
describe "getMemberIds", ->
beforeEach ->
@@ -1,83 +1,8 @@
request = require("request")
expect = require("chai").expect
async = require "async"
settings = require("settings-sharelatex")
{db} = require("../../../app/js/infrastructure/mongojs")
count = 0
BASE_URL = "http://localhost:3000"
request = request.defaults({
baseUrl: BASE_URL,
followRedirect: false
})
class User
constructor: (options = {}) ->
@email = "acceptance-test-#{count}@example.com"
@password = "acceptance-test-#{count}-password"
count++
@jar = request.jar()
@request = request.defaults({
jar: @jar
})
login: (callback = (error) ->) ->
@getCsrfToken (error) =>
return callback(error) if error?
@request.post {
url: "/register" # Register will log in, but also ensure user exists
json:
email: @email
password: @password
}, (error, response, body) =>
return callback(error) if error?
db.users.findOne {email: @email}, (error, user) =>
return callback(error) if error?
@id = user?._id?.toString()
callback()
createProject: (name, callback = (error, project_id) ->) ->
@request.post {
url: "/project/new",
json:
projectName: name
}, (error, response, body) ->
return callback(error) if error?
if !body?.project_id?
console.error "SOMETHING WENT WRONG CREATING PROJECT", response.statusCode, response.headers["location"], body
callback(null, body.project_id)
addUserToProject: (project_id, email, privileges, callback = (error, user) ->) ->
@request.post {
url: "/project/#{project_id}/users",
json: {email, privileges}
}, (error, response, body) ->
return callback(error) if error?
callback(null, body.user)
makePublic: (project_id, level, callback = (error) ->) ->
@request.post {
url: "/project/#{project_id}/settings/admin",
json:
publicAccessLevel: level
}, (error, response, body) ->
return callback(error) if error?
callback(null)
getCsrfToken: (callback = (error) ->) ->
@request.get {
url: "/register"
}, (err, response, body) =>
return callback(error) if error?
csrfMatches = body.match("window.csrfToken = \"(.*?)\";")
if !csrfMatches?
return callback(new Error("no csrf token found"))
@request = @request.defaults({
headers:
"x-csrf-token": csrfMatches[1]
})
callback()
async = require("async")
User = require "./helpers/User"
request = require "./helpers/request"
settings = require "settings-sharelatex"
try_read_access = (user, project_id, test, callback) ->
async.series [
@@ -0,0 +1,21 @@
expect = require("chai").expect
async = require("async")
User = require "./helpers/User"
describe "Project CRUD", ->
before (done) ->
@user = new User()
@user.login done
describe "when project doesn't exist", ->
it "should return 404", (done) ->
@user.request.get "/project/aaaaaaaaaaaaaaaaaaaaaaaa", (err, res, body) ->
expect(res.statusCode).to.equal 404
done()
describe "when project has malformed id", ->
it "should return 404", (done) ->
@user.request.get "/project/blah", (err, res, body) ->
expect(res.statusCode).to.equal 404
done()
@@ -0,0 +1,74 @@
request = require("./request")
settings = require("settings-sharelatex")
{db} = require("../../../../app/js/infrastructure/mongojs")
count = 0
class User
constructor: (options = {}) ->
@email = "acceptance-test-#{count}@example.com"
@password = "acceptance-test-#{count}-password"
count++
@jar = request.jar()
@request = request.defaults({
jar: @jar
})
login: (callback = (error) ->) ->
@getCsrfToken (error) =>
return callback(error) if error?
@request.post {
url: "/register" # Register will log in, but also ensure user exists
json:
email: @email
password: @password
}, (error, response, body) =>
return callback(error) if error?
db.users.findOne {email: @email}, (error, user) =>
return callback(error) if error?
@id = user?._id?.toString()
callback()
createProject: (name, callback = (error, project_id) ->) ->
@request.post {
url: "/project/new",
json:
projectName: name
}, (error, response, body) ->
return callback(error) if error?
if !body?.project_id?
console.error "SOMETHING WENT WRONG CREATING PROJECT", response.statusCode, response.headers["location"], body
callback(null, body.project_id)
addUserToProject: (project_id, email, privileges, callback = (error, user) ->) ->
@request.post {
url: "/project/#{project_id}/users",
json: {email, privileges}
}, (error, response, body) ->
return callback(error) if error?
callback(null, body.user)
makePublic: (project_id, level, callback = (error) ->) ->
@request.post {
url: "/project/#{project_id}/settings/admin",
json:
publicAccessLevel: level
}, (error, response, body) ->
return callback(error) if error?
callback(null)
getCsrfToken: (callback = (error) ->) ->
@request.get {
url: "/register"
}, (err, response, body) =>
return callback(error) if error?
csrfMatches = body.match("window.csrfToken = \"(.*?)\";")
if !csrfMatches?
return callback(new Error("no csrf token found"))
@request = @request.defaults({
headers:
"x-csrf-token": csrfMatches[1]
})
callback()
module.exports = User
@@ -0,0 +1,5 @@
BASE_URL = "http://localhost:3000"
module.exports = require("request").defaults({
baseUrl: BASE_URL,
followRedirect: false
})