diff --git a/services/web/.gitignore b/services/web/.gitignore index f8a1fc0842..a3f982ef53 100644 --- a/services/web/.gitignore +++ b/services/web/.gitignore @@ -40,6 +40,7 @@ app.js app/js/* test/UnitTests/js/* test/smoke/js/* +test/acceptance/js/* cookies.txt requestQueueWorker.js TpdsWorker.js diff --git a/services/web/Gruntfile.coffee b/services/web/Gruntfile.coffee index 7d49df07af..3cfe803b17 100644 --- a/services/web/Gruntfile.coffee +++ b/services/web/Gruntfile.coffee @@ -71,6 +71,14 @@ module.exports = (grunt) -> dest: 'test/UnitTests/js/', ext: '.js' + acceptance_tests: + expand: true, + flatten: false, + cwd: 'test/acceptance/coffee', + src: ['**/*.coffee'], + dest: 'test/acceptance/js/', + ext: '.js' + less: app: files: @@ -119,6 +127,7 @@ module.exports = (grunt) -> clean: app: ["app/js"] unit_tests: ["test/UnitTests/js"] + acceptance_tests: ["test/acceptance/js"] mochaTest: unit: @@ -131,6 +140,11 @@ module.exports = (grunt) -> options: reporter: grunt.option('reporter') or 'spec' grep: grunt.option("grep") + acceptance: + src: ["test/acceptance/js/#{grunt.option('feature') or '**'}/*.js"] + options: + reporter: grunt.option('reporter') or 'spec' + grep: grunt.option("grep") "git-rev-parse": version: @@ -184,6 +198,7 @@ module.exports = (grunt) -> ] "Test tasks": [ "test:unit" + "test:acceptance" ] "Run tasks": [ "run" @@ -290,6 +305,7 @@ module.exports = (grunt) -> grunt.registerTask 'compile:css', 'Compile the less files to css', ['less'] grunt.registerTask 'compile:minify', 'Concat and minify the client side js', ['requirejs', "file_append"] grunt.registerTask 'compile:unit_tests', 'Compile the unit tests', ['clean:unit_tests', 'coffee:unit_tests'] + grunt.registerTask 'compile:acceptance_tests', 'Compile the acceptance tests', ['clean:acceptance_tests', 'coffee:acceptance_tests'] grunt.registerTask 'compile:smoke_tests', 'Compile the smoke tests', ['coffee:smoke_tests'] grunt.registerTask 'compile:tests', 'Compile all the tests', ['compile:smoke_tests', 'compile:unit_tests'] grunt.registerTask 'compile', 'Compiles everything need to run web-sharelatex', ['compile:server', 'compile:client', 'compile:css'] @@ -297,6 +313,7 @@ module.exports = (grunt) -> grunt.registerTask 'install', "Compile everything when installing as an npm module", ['compile'] grunt.registerTask 'test:unit', 'Run the unit tests (use --grep= or --feature= for individual tests)', ['compile:server', 'compile:modules:server', 'compile:unit_tests', 'compile:modules:unit_tests', 'mochaTest:unit'].concat(moduleUnitTestTasks) + grunt.registerTask 'test:acceptance', 'Run the acceptance tests (use --grep= or --feature= for individual tests)', ['compile:acceptance_tests', 'mochaTest:acceptance'] grunt.registerTask 'test:smoke', 'Run the smoke tests', ['compile:smoke_tests', 'mochaTest:smoke'] grunt.registerTask 'test:modules:unit', 'Run the unit tests for the modules', ['compile:modules:server', 'compile:modules:unit_tests'].concat(moduleUnitTestTasks) diff --git a/services/web/package.json b/services/web/package.json index 637df85a8f..021d86f6d7 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -44,7 +44,8 @@ "redback": "0.4.0", "redis": "0.10.1", "redis-sharelatex": "0.0.9", - "request": "2.34.0", + "request": "^2.69.0", + "requests": "^0.1.7", "rimraf": "2.2.6", "sanitizer": "0.1.1", "settings-sharelatex": "git+https://github.com/sharelatex/settings-sharelatex.git#v1.0.0", diff --git a/services/web/test/acceptance/coffee/AuthorizationTests.coffee b/services/web/test/acceptance/coffee/AuthorizationTests.coffee new file mode 100644 index 0000000000..d5c1602ca6 --- /dev/null +++ b/services/web/test/acceptance/coffee/AuthorizationTests.coffee @@ -0,0 +1,86 @@ +request = require("request") +expect = require("chai").expect + +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? + callback() + + createProject: (name, callback = (error, project_id) ->) -> + @request.post { + url: "/project/new", + json: + projectName: name + }, (error, response, body) -> + return callback(error) if error? + callback(null, body.project_id) + + 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() + +describe "Authorization", -> + describe "private project", -> + before (done) -> + @owner = new User() + @other = new User() + @owner.login (error) => + return done(error) if error? + @other.login (error) => + return done(error) if error? + @owner.createProject "private-project", (error, project_id) => + return done(error) if error? + @project_id = project_id + done() + + it "should allow the owner to access it", (done) -> + @owner.request.get "/project/#{@project_id}", (error, response, body) -> + expect(response.statusCode).to.equal 200 + done() + + it "should not allow another user to access it", (done) -> + @other.request.get "/project/#{@project_id}", (error, response, body) -> + expect(response.statusCode).to.equal 302 + expect(response.headers.location).to.equal "/restricted" + done() + + it "should not allow anonymous user to access it", (done) -> + request.get "/project/#{@project_id}", (error, response, body) -> + expect(response.statusCode).to.equal 302 + expect(response.headers.location).to.equal "/login" + done() \ No newline at end of file